Skip to content

🛡️ Sentinel: [HIGH] Fix Path Traversal Symlink Bypass & File Server Exceptions#91

Open
socialawy-dev wants to merge 1 commit into
mainfrom
sentinel/path-traversal-symlink-bypass-12193734970889885254
Open

🛡️ Sentinel: [HIGH] Fix Path Traversal Symlink Bypass & File Server Exceptions#91
socialawy-dev wants to merge 1 commit into
mainfrom
sentinel/path-traversal-symlink-bypass-12193734970889885254

Conversation

@socialawy-dev
Copy link
Copy Markdown
Collaborator

🚨 Severity: HIGH
💡 Vulnerability: Path traversal via symlink bypass and potential denial-of-service/fail-open from unhandled path resolution exceptions in SafeStaticFiles.
🎯 Impact: Attackers could potentially bypass static directory restrictions using maliciously crafted symlinks, or cause unhandled 500 server errors (DoS) / fail open states by passing invalid (e.g. None) paths to the SafeStaticFiles class.
🔧 Fix: Upgraded validate_path_within to strictly use Path.resolve().is_relative_to() and broadened exception handling. Added strict type checks and a try-catch block around the static file access gateway.
✅ Verification: Ran full pytest test suite (including test_security.py and test_server_routes.py) to ensure all tests passed successfully.


PR created automatically by Jules for task 12193734970889885254 started by @socialawy

- Replaces string-based `os.path.abspath` comparisons with robust `Path.resolve().is_relative_to()` check in `validate_path_within` to prevent symlink traversal.
- Adds comprehensive exception handling in `validate_path_within` to catch TypeError/None inputs securely.
- Wraps `SafeStaticFiles.get_response` in a try-except block to gracefully catch malformed/None paths and return HTTP 400 instead of failing open or 500ing.

Co-authored-by: socialawy <24765060+socialawy@users.noreply.github.com>
@google-labs-jules
Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

if path is None or root is None:
return False

resolved_root = root.resolve()
return False

resolved_root = root.resolve()
resolved_path = path.resolve()
Copy link
Copy Markdown

@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 addresses path traversal and symlink bypass vulnerabilities by refactoring path validation logic to use Path.resolve() and is_relative_to in the security utilities. It also enhances the SafeStaticFiles middleware with a fail-closed error handling strategy and explicit input validation. Additionally, development dependencies for mypy and ruff were updated. Review feedback highlights that the blacklist check in the middleware remains lexical and could still be bypassed via symlinks, suggesting a more robust check for .env files and path resolution before validation.

Comment on lines +35 to +38
if "00_config" in p.parts or p.name.startswith(".env") or ".git" in p.parts:
raise HTTPException(
status_code=403, detail="Access denied to sensitive resource"
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-high high

The blacklist check in SafeStaticFiles remains purely lexical and does not account for symlinks, which contradicts the pull request's stated goal of fixing symlink bypasses. An attacker could potentially bypass these restrictions by using a symlink that points to a sensitive directory but does not contain the blacklisted strings in its path (e.g., ln -s 00_config public_link). To fully address this, the middleware should resolve the requested path against the filesystem root before checking. Additionally, the current .env check only validates the last component of the path (p.name); using any() on p.parts would more robustly block access to any directory or file starting with .env.

Suggested change
if "00_config" in p.parts or p.name.startswith(".env") or ".git" in p.parts:
raise HTTPException(
status_code=403, detail="Access denied to sensitive resource"
)
if "00_config" in p.parts or ".git" in p.parts or any(part.startswith(".env") for part in p.parts):
raise HTTPException(
status_code=403, detail="Access denied to sensitive resource"
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants