Skip to content

T8#1747

Merged
nmaguiar merged 13 commits intomasterfrom
t8
Mar 9, 2026
Merged

T8#1747
nmaguiar merged 13 commits intomasterfrom
t8

Conversation

@nmaguiar
Copy link
Collaborator

@nmaguiar nmaguiar commented Mar 9, 2026

This pull request introduces several important security and correctness improvements to the file serving logic in both src/com/nwu/httpd/responses/FileResponse.java and src/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:

  • Refactored URI handling to robustly extract and sanitize the relative path, including removing leading slashes, handling null bytes, and preventing directory traversal attacks by checking for .. in the path. Added canonical path checks to ensure files served are within the intended directory. [1] [2] [3] [4]
  • Improved directory listing and navigation by using a sanitized uriForLinks variable for all links and display logic, ensuring correct and safe URLs in directory listings. [1] [2] [3] [4] [5] [6]
  • Added validation for HTTP range requests to return a RANGE_NOT_SATISFIABLE response if the requested byte range is invalid, and simplified file input stream handling for better reliability. [1] [2]

Dependency updates:

  • Updated Jetty dependencies (jetty-io and jetty-util) from version 12.1.6 to 12.1.7 in pom.xml for improved stability and security.

JavaScript minor improvements:

  • Replaced usage of $do with $doV in two locations in js/openaf.js for improved asynchronous control flow. [1] [2]

nmaguiar and others added 9 commits March 5, 2026 21:16
- 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>
- Updated jetty-io and jetty-util libraries to the latest 12.1.7 release.\n- No functional changes, just dependency updates.
@nmaguiar nmaguiar requested a review from Copilot March 9, 2026 09:52
@nmaguiar nmaguiar self-assigned this Mar 9, 2026
@nmaguiar nmaguiar added enhancement dependencies Pull requests that update a dependency file labels Mar 9, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 FileResponse classes to prevent directory traversal attacks via null bytes, .. segments, and canonical path checks; improved directory listing link generation using a sanitized uriForLinks variable
  • 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 $do with $doV in two places in js/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.

Comment on lines +108 to +112
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.");
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +239 to +243
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");
}
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +246 to +252
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;
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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;
}

Copilot uses AI. Check for mistakes.

// Prohibit getting out of current directory
if (relativeUri.startsWith("..") || relativeUri.endsWith("..")
|| relativeUri.indexOf("../") >= 0)
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
|| relativeUri.indexOf("../") >= 0)
|| relativeUri.indexOf("../") >= 0
|| relativeUri.indexOf(".." + File.separator) >= 0)

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI commented Mar 9, 2026

@nmaguiar I've opened a new pull request, #1749, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI commented Mar 9, 2026

@nmaguiar I've opened a new pull request, #1750, to work on those changes. Once the pull request is ready, I'll request review from you.

@nmaguiar nmaguiar merged commit 45c00ae into master Mar 9, 2026
1 of 2 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in Continuous Enhancement Mar 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file enhancement

Projects

Development

Successfully merging this pull request may close these issues.

3 participants