Skip to content

🐛 bug: fix sanitizePath validation logic#4064

Merged
ReneWerner87 merged 1 commit intomainfrom
update-sanitizepath-to-handle-backslashes
Feb 8, 2026
Merged

🐛 bug: fix sanitizePath validation logic#4064
ReneWerner87 merged 1 commit intomainfrom
update-sanitizepath-to-handle-backslashes

Conversation

@gaby
Copy link
Member

@gaby gaby commented Feb 8, 2026

Motivation

  • Prevent directory traversal and Windows/UNC/drive-letter escape vectors when serving static files and ensure consistent behavior for both OS-backed filesystems and generic fs.FS inputs.

Description

  • Harden sanitizePath to normalize backslashes, reject residual backslashes and null bytes, detect and reject residual .. segments after cleaning, and disallow UNC/double-slash and Windows volume/drive prefixes when filesystem == nil.
  • Preserve existing behavior for filesystem != nil by using fs.ValidPath, returning "/" for an empty filesystem path, and preserving trailing-slash semantics.
  • Expand middleware/static/static_test.go with comprehensive cases for encoded/double-encoded traversals, Windows/UNC vectors, os.DirFS scenarios, and add/adjust benchmarks to exercise sanitizePath variations.

@gaby gaby requested a review from a team as a code owner February 8, 2026 06:37
Copilot AI review requested due to automatic review settings February 8, 2026 06:37
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 8, 2026

Walkthrough

Path sanitization in the static middleware is strengthened with stricter validation rules, including early backslash rejection, normalization via filepath.ToSlash, double-slash detection, and filesystem-aware checks for UNC paths and drive letters. Test coverage expands significantly with path traversal and encoding attack scenarios.

Changes

Cohort / File(s) Summary
Static Middleware Path Sanitization
middleware/static/static.go, middleware/static/static_test.go
Enhanced path validation with early backslash rejection, normalized slash conversion, double-slash checking, filesystem-aware UNC/drive-letter rejection, and expanded test suite covering encoded traversals, mixed encodings, and Windows-specific scenarios.
Router Error Handling
router.go
Adds explicit return statement after error handling in requestHandler to short-circuit further processing on error paths.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PR #3595 — Modifies sanitizePath logic in the static middleware and expands path-traversal test coverage with similar validation patterns.
  • PR #3600 — Updates static middleware path sanitization and broadens path-traversal tests following comparable security hardening approaches.
  • PR #3673 — Modifies the same sanitizePath implementation with path normalization and trailing-slash handling adjustments.

Suggested labels

🧹 Updates, v3

Suggested reviewers

  • sixcolors
  • efectn
  • ReneWerner87

Poem

🐰 A hoppy tale of safer paths,
Where backslashes meet their aftermath,
Slashes normalized, double-checks in place,
No traversals shall find their way through this space!
Windows and Unix now shake paw in peace.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title contains a bug emoji and references 'sanitizePath validation logic', which directly aligns with the main change of hardening path sanitization in the middleware/static module.
Description check ✅ Passed The description provides clear motivation, describes the implementation changes to sanitizePath, explains preservation of existing behavior, and references test expansion. However, it omits most checklist items from the template including benchmarks, documentation, changelog, and type-of-change indicators.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch update-sanitizepath-to-handle-backslashes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @gaby, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on enhancing the security and robustness of static file serving by implementing stricter path sanitization. The primary goal is to prevent directory traversal vulnerabilities, including those specific to Windows environments, by introducing comprehensive validation rules within the sanitizePath function. This ensures that all incoming paths are securely processed, whether they originate from the operating system's filesystem or a generic fs.FS interface, thereby safeguarding against unauthorized file access. The changes are supported by an extensive update to the test suite, covering a broad array of potential attack vectors.

Highlights

  • Security Hardening: The sanitizePath function has been significantly hardened to prevent directory traversal and various Windows-specific escape vectors, ensuring more robust security for static file serving.
  • Path Validation Logic: New checks were introduced in sanitizePath to reject paths containing backslashes, null bytes, residual .. segments after cleaning, and to disallow UNC/double-slash and Windows volume/drive prefixes when filesystem is nil.
  • Test Coverage Expansion: Comprehensive new test cases have been added to middleware/static/static_test.go to cover a wide range of encoded/double-encoded traversals, Windows/UNC vectors, and os.DirFS scenarios, ensuring the new sanitization logic is thoroughly tested.
  • Consistent Filesystem Behavior: The sanitizePath function now maintains consistent behavior for filesystem != nil inputs, utilizing fs.ValidPath and preserving trailing-slash semantics, while also returning "/" for empty filesystem paths.
  • Error Handling Improvement: A return statement was added in router.go's requestHandler after error handling, ensuring that execution properly terminates following an error.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • middleware/static/static.go
    • Added slices package import.
    • Modified sanitizePath to reject paths containing backslashes (\) when filesystem is nil.
    • Modified sanitizePath to reject paths containing null bytes (\x00).
    • Normalized paths using filepath.ToSlash before cleaning.
    • Implemented checks to reject paths with residual .. segments after cleaning.
    • Added logic to disallow UNC paths (//server/share) and Windows drive letters (C:/) when filesystem is nil.
    • Adjusted sanitizePath logic for filesystem != nil to use the trimmed path, preserving fs.ValidPath behavior and returning "/" for empty paths.
  • middleware/static/static_test.go
    • Added numerous new test cases to Test_Static_PathTraversal for various encoded and double-encoded traversal attempts.
    • Expanded Test_Static_PathTraversal_WindowsOnly with new tests covering Windows-specific traversal vectors, including backslashes, UNC paths, and drive letters.
    • Updated Test_SanitizePath with new valid path scenarios, including dot segments, encoded spaces, and os.DirFS specific behaviors.
    • Added extensive new error test cases to Test_SanitizePath_Error for various invalid path patterns, such as encoded backslashes, double slashes, drive letters, and UNC paths.
  • router.go
    • Added a return statement after the ErrorHandler call in requestHandler to ensure proper control flow after an error is handled.
Activity
  • make audit failed due to an external govulncheck fetch error (502 Bad Gateway), noted as an external service issue.
  • make generate completed successfully.
  • make betteralign completed successfully.
  • make modernize completed successfully.
  • make format completed successfully.
  • make lint completed successfully and reported 0 issues.
  • make test completed successfully, reporting 2662 tests, 1 skipped in 151.090s.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@ReneWerner87 ReneWerner87 added this to v3 Feb 8, 2026
@ReneWerner87 ReneWerner87 added this to the v3 milestone Feb 8, 2026
@gaby gaby changed the title 🧹 chore: harden sanitizePath and extend static path tests 🐛 bug: fix sanitizePath validation logic Feb 8, 2026
@gaby gaby removed the 🧹 Updates label Feb 8, 2026
@codecov
Copy link

codecov bot commented Feb 8, 2026

Codecov Report

❌ Patch coverage is 66.66667% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.05%. Comparing base (8b5d061) to head (8e3fbb3).
⚠️ Report is 28 commits behind head on main.

Files with missing lines Patch % Lines
middleware/static/static.go 65.21% 4 Missing and 4 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4064      +/-   ##
==========================================
- Coverage   91.10%   91.05%   -0.06%     
==========================================
  Files         119      119              
  Lines       11203    11229      +26     
==========================================
+ Hits        10207    10225      +18     
- Misses        630      634       +4     
- Partials      366      370       +4     
Flag Coverage Δ
unittests 91.05% <66.66%> (-0.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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 hardens static file path sanitization to better prevent traversal and Windows/UNC/drive-letter escape vectors, and expands static middleware tests/benchmarks to validate those behaviors across OS-backed and fs.FS filesystems.

Changes:

  • Update sanitizePath to normalize separators, reject backslashes/null bytes, and add Windows/UNC/volume-prefix blocking (when filesystem == nil) while preserving fs.ValidPath behavior for fs.FS.
  • Expand middleware/static/static_test.go with many additional traversal and Windows/UNC cases, plus benchmark coverage.
  • Ensure the router request handler exits immediately after error handling.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
router.go Adds an explicit return after error handling in requestHandler.
middleware/static/static.go Strengthens path sanitization/validation to reduce traversal and Windows path escape vectors.
middleware/static/static_test.go Extends traversal/path sanitization tests and benchmarks for more comprehensive coverage.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
middleware/static/static_test.go (1)

1086-1096: ⚠️ Potential issue | 🟡 Minor

Bug: body in the else branch refers to the valid-request body (line 1071), not the blocked-request response.

In assertTraversalBlocked, when status != 404 (i.e., status 400), the assertion on line 1093 checks body from the outer scope (the valid CSS response from line 1071) instead of reading resp.Body. Compare with Test_Static_PathTraversal (line 963) which correctly reads from resp.Body inside the helper.

🐛 Proposed fix
 		if status == 404 {
 			respBody, err := io.ReadAll(resp.Body)
 			require.NoError(t, err)
 			require.Contains(t, string(respBody), "Not Found",
 				"Blocked traversal should have a \"Not Found\" message for %s", path)
 		} else {
-			require.Contains(t, string(body), "Are you a hacker?",
+			respBody, err := io.ReadAll(resp.Body)
+			require.NoError(t, err)
+			require.Contains(t, string(respBody), "Are you a hacker?",
 				"Blocked traversal should have a \"Not Found\" message for %s", path)
 		}
🧹 Nitpick comments (3)
middleware/static/static.go (2)

73-78: strings.Split + slices.Contains allocates on every request for a check that is unreachable after pathpkg.Clean("/" + …).

pathpkg.Clean with a rooted prefix already eliminates all .. segments (they resolve against /), so this block is pure defense-in-depth and will never trigger. If you want to keep it, consider a cheaper scan that avoids the allocation:

♻️ Suggested zero-alloc alternative
-	trimmed := utils.TrimLeft(s, '/')
-	if trimmed != "" {
-		if slices.Contains(strings.Split(trimmed, "/"), "..") {
-			return nil, ErrInvalidPath
-		}
-	}
+	trimmed := utils.TrimLeft(s, '/')
+	if trimmed != "" {
+		// Fast path: if ".." doesn't appear at all, skip the detailed check.
+		if strings.Contains(trimmed, "..") {
+			for part := range strings.SplitSeq(trimmed, "/") {
+				if part == ".." {
+					return nil, ErrInvalidPath
+				}
+			}
+		}
+	}

80-97: filepath.VolumeName is a no-op on Linux — the manual drive-letter check on lines 88-93 is the real cross-platform guard.

filepath.VolumeName (line 85) returns "" on non-Windows OSes regardless of input, so it will never trigger there. The manual check on lines 88-93 is the one that actually provides cross-platform protection for drive-letter paths. This is fine as-is, but worth a brief comment so future maintainers know the layering.

Also, normalizedClean (line 81) is filepath.ToSlash(trimmed) where trimmed already had backslashes rejected (line 57-59) and was filepath.ToSlash'd (line 66), making this second ToSlash redundant. Similarly, the "//" prefix check on line 82 is unreachable because trimmed has leading slashes stripped, and the check on line 94 is unreachable because pathpkg.Clean normalizes multiple leading slashes.

The redundancy isn't harmful — defense-in-depth is reasonable for security-critical code — but inline comments would clarify intent.

middleware/static/static_test.go (1)

1098-1134: A few test cases are duplicated within this function.

Lines 1107/1117, 1111/1121 assert the same paths. Not harmful, but the duplicates could be removed for clarity.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request hardens the sanitizePath function to prevent various path traversal vulnerabilities and adds extensive test cases to cover these scenarios. The changes are well-implemented and significantly improve security when serving static files. I've found a small opportunity to simplify the new logic in sanitizePath by removing some redundant checks, which should improve code clarity and maintainability. The fix in router.go is also correct.

@ReneWerner87 ReneWerner87 merged commit 5913370 into main Feb 8, 2026
31 of 33 checks passed
@ReneWerner87 ReneWerner87 deleted the update-sanitizepath-to-handle-backslashes branch February 8, 2026 21:02
@github-project-automation github-project-automation bot moved this to Done in v3 Feb 8, 2026
@ReneWerner87 ReneWerner87 modified the milestones: v3, v3.1.0 Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants