Conversation
- Refactored serveFile logic to use canonical paths and stricter validation - Enhanced security by preventing directory traversal and invalid path access - Improved code clarity and robustness for file serving in both modules
Bumps org.eclipse.jetty:jetty-util from 12.1.6 to 12.1.7. --- updated-dependencies: - dependency-name: org.eclipse.jetty:jetty-util dependency-version: 12.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps org.eclipse.jetty:jetty-io from 12.1.6 to 12.1.7. --- updated-dependencies: - dependency-name: org.eclipse.jetty:jetty-io dependency-version: 12.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
…jetty-jetty-io-12.1.7
…jetty-jetty-util-12.1.7
- Updated jetty-io and jetty-util libraries to the latest 12.1.7 release.\n- No functional changes, just dependency updates.
There was a problem hiding this comment.
Pull request overview
This PR introduces security and correctness improvements to the HTTP file serving logic in both src/com/nwu/httpd/responses/FileResponse.java and src/com/nwu2/httpd/responses/FileResponse.java, updates Jetty dependencies, and makes minor JavaScript improvements.
Changes:
- Refactored URI path handling in both
FileResponseclasses to prevent directory traversal attacks via null bytes,..segments, and canonical path checks; improved directory listing link generation using a sanitizeduriForLinksvariable - Added HTTP 416 (Range Not Satisfiable) validation for byte-range requests and simplified file stream handling
- Updated Jetty dependencies from 12.1.6 to 12.1.7 and replaced
$dowith$doVin two places injs/openaf.js
Reviewed changes
Copilot reviewed 4 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
src/com/nwu2/httpd/responses/FileResponse.java |
Security improvements: null-byte blocking, canonical path check, improved directory listing, range request validation |
src/com/nwu/httpd/responses/FileResponse.java |
Same security improvements as nwu2 (mirrored change) |
pom.xml |
Bump Jetty jetty-io and jetty-util from 12.1.6 to 12.1.7 |
js/openaf.js |
Replace $do with $doV for async stream control flow; fix indentation |
js/oafp.js |
Version bump and minified code refactoring/optimizations |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (relativeUri.startsWith("..") || relativeUri.endsWith("..") | ||
| || relativeUri.indexOf("../") >= 0) | ||
| return new com.nwu.httpd.responses.SimpleResponse(httpd, | ||
| Codes.HTTP_FORBIDDEN, Codes.MIME_PLAINTEXT, | ||
| "FORBIDDEN: Won't serve ../ for security reasons."); |
There was a problem hiding this comment.
Same incomplete traversal check as in nwu2: only ../ is checked but not ..\. The canonical path check provides a safety net, but the explicit check should be comprehensive.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| if (startFrom < 0 || startFrom >= f.length()) { | ||
| return new com.nwu2.httpd.responses.SimpleResponse(httpd, | ||
| com.nwu2.httpd.NanoHTTPD.Response.Status.RANGE_NOT_SATISFIABLE, Codes.MIME_PLAINTEXT, | ||
| "Requested Range Not Satisfiable"); | ||
| } |
There was a problem hiding this comment.
The RANGE_NOT_SATISFIABLE check at line 239 fires even when no range header was provided (startFrom defaults to 0) and the file is empty (f.length() == 0). Since startFrom < 0 is always false for the default of 0, and startFrom >= f.length() is true for a 0-byte file, a valid request for an empty file will be incorrectly rejected with a 416 error instead of a 200 OK.
More critically, the check should only be applied when a range header was actually present. When range is null, startFrom remains 0 and the response should always be served normally. The guard should be: if (range != null && (startFrom < 0 || startFrom >= f.length())).
Additionally, if startFrom is 0 and no range was requested, returning a 416 for an empty file is incorrect behavior.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| fis.skip(startFrom); | ||
| com.nwu.httpd.responses.Response r = new com.nwu.httpd.responses.SimpleResponse( | ||
| httpd, Codes.HTTP_OK, mime, fis); | ||
| r.addHeader("Content-length", "" + (f.length() - startFrom)); | ||
| r.addHeader("Content-range", "" + startFrom + "-" | ||
| + (f.length() - 1) + "/" + f.length()); | ||
| return r; |
There was a problem hiding this comment.
Same resource leak issue as in nwu2: the FileInputStream opened at line 245 is not protected by a try-finally block. If an exception occurs between new FileInputStream(f) and the return r, the stream will be leaked.
| fis.skip(startFrom); | |
| com.nwu.httpd.responses.Response r = new com.nwu.httpd.responses.SimpleResponse( | |
| httpd, Codes.HTTP_OK, mime, fis); | |
| r.addHeader("Content-length", "" + (f.length() - startFrom)); | |
| r.addHeader("Content-range", "" + startFrom + "-" | |
| + (f.length() - 1) + "/" + f.length()); | |
| return r; | |
| try { | |
| fis.skip(startFrom); | |
| com.nwu.httpd.responses.Response r = new com.nwu.httpd.responses.SimpleResponse( | |
| httpd, Codes.HTTP_OK, mime, fis); | |
| r.addHeader("Content-length", "" + (f.length() - startFrom)); | |
| r.addHeader("Content-range", "" + startFrom + "-" | |
| + (f.length() - 1) + "/" + f.length()); | |
| return r; | |
| } catch (IOException e) { | |
| try { | |
| fis.close(); | |
| } catch (IOException ignore) { | |
| // ignore secondary exception during close | |
| } | |
| throw e; | |
| } |
|
|
||
| // Prohibit getting out of current directory | ||
| if (relativeUri.startsWith("..") || relativeUri.endsWith("..") | ||
| || relativeUri.indexOf("../") >= 0) |
There was a problem hiding this comment.
The .. path traversal check at line 108–112 is incomplete: it checks for ../ (forward slash) but not ..\ (backslash). On Windows, a path segment like ..\ could bypass this check. While backslashes are normalized to forward slashes at line 97 (replace('\\', '/')), this normalization only covers literal backslashes in the input, not encoded variants (e.g., %5C). URL-decoded traversal sequences could still slip through. The canonical path check added later provides defense-in-depth, but the traversal check should also include ".."+File.separator for completeness.
| || relativeUri.indexOf("../") >= 0) | |
| || relativeUri.indexOf("../") >= 0 | |
| || relativeUri.indexOf(".." + File.separator) >= 0) |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This pull request introduces several important security and correctness improvements to the file serving logic in both
src/com/nwu/httpd/responses/FileResponse.javaandsrc/com/nwu2/httpd/responses/FileResponse.java, as well as minor dependency and JavaScript updates. The main focus is on tightening path validation to prevent directory traversal and invalid path access, improving directory listing and file serving behavior, and updating dependencies.File serving and security improvements:
..in the path. Added canonical path checks to ensure files served are within the intended directory. [1] [2] [3] [4]uriForLinksvariable for all links and display logic, ensuring correct and safe URLs in directory listings. [1] [2] [3] [4] [5] [6]RANGE_NOT_SATISFIABLEresponse if the requested byte range is invalid, and simplified file input stream handling for better reliability. [1] [2]Dependency updates:
jetty-ioandjetty-util) from version 12.1.6 to 12.1.7 inpom.xmlfor improved stability and security.JavaScript minor improvements:
$dowith$doVin two locations injs/openaf.jsfor improved asynchronous control flow. [1] [2]