[security] Prevent SSRF attacks via path traversal in component file handling#13733
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
This stack of pull requests is managed by Graphite. Learn more about stacking. |
✅ PR preview is ready!
|
There was a problem hiding this comment.
Pull request overview
Addresses an SSRF risk on Windows by adding early-path validation to block UNC/absolute/traversal inputs before any filesystem resolution occurs.
Changes:
- Added
_is_unsafe_pathand used it inbuild_safe_abspathto reject UNC/absolute/traversal paths before callingos.path.realpath. - Expanded unit tests to cover UNC paths, Windows drive paths, traversal patterns, null bytes, and mixed separators.
- Updated existing normalization-related tests to reflect the stricter traversal policy.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
lib/streamlit/web/server/component_file_utils.py |
Adds early path validation to prevent UNC-triggered network access and harden path resolution. |
lib/tests/streamlit/web/server/component_file_utils_test.py |
Adds/updates unit tests to validate the new SSRF/traversal defenses and guard against regressions. |
📈 Frontend coverage change detectedThe frontend unit test (vitest) coverage has increased by 0.0500%
🎉 Great job on improving test coverage! |
SummaryThis PR adds security enhancements to prevent Server-Side Request Forgery (SSRF) vulnerabilities in component file handling. The key changes are:
Code QualityThe implementation is well-structured and follows Streamlit's coding standards: Strengths:
Code structure in # Check order is logical and well-commented:
# 1. Null bytes (path truncation attacks)
# 2. UNC paths (Windows network shares)
# 3. Windows drive letters (case-insensitive)
# 4. Rooted absolute paths
# 5. Path traversal segmentsThe path traversal detection correctly handles:
Test CoverageExcellent test coverage with 211 new lines of tests. The tests follow best practices from the Python test guide:
Test categories covered:
Minor observation: The import Backwards CompatibilityBreaking change: Paths containing
The change is unlikely to affect legitimate users since component URLs are typically clean paths like Security & RiskSecurity assessment: GOOD The fix correctly addresses the SSRF vulnerability:
Minor edge case not covered but acceptable: RecommendationsNo blocking issues found. The following are optional improvements:
VerdictAPPROVED: This is a well-implemented security fix with comprehensive test coverage. The code follows Streamlit's conventions, the breaking change is justified and documented, and no security bypasses or regressions were identified. The PR is ready for merge. This is an automated AI review using |
7e0c6c8 to
ff25af4
Compare
SummaryThis PR centralizes path safety validation into a shared helper and applies it before any filesystem resolution in component and app static file handling, preventing UNC/drive-based SSRF vectors and tightening traversal checks. It also adds comprehensive Python unit tests for unsafe patterns and regression coverage around early rejection. Code QualityThe refactor is clean and keeps path security checks in one place ( Test CoverageUnit tests were added and are thorough, including regression checks that Backwards CompatibilityBehavior is intentionally stricter: paths containing Security & RiskSecurity posture is improved: unsafe path patterns are rejected before any Recommendations
VerdictAPPROVED: Security fix is well-scoped, tests are comprehensive, and no blocking issues were found. This is an automated AI review using |
f586843 to
e7d904e
Compare
5c81c2d to
0c2712e
Compare
SummaryThis PR hardens Streamlit’s static/component file-path handling to prevent Windows UNC-path SSRF/NTLM leakage by introducing a shared Code Quality
Test Coverage
Backwards Compatibility
Security & Risk
Recommendations
VerdictAPPROVED: The security fix is well-scoped, defensively implemented (early validation), and backed by strong unit/integration tests with a key regression check that prevents reintroducing the SSRF vector. This is an automated AI review using |
SummaryThis PR centralizes path validation into a shared security helper and applies it to component asset resolution and app static file handling, preventing UNC/drive-based SSRF and traversal patterns before filesystem operations. It also adds targeted unit tests to document the security invariants and regression risks. Code QualityThe refactor is clear and well-scoped: the shared Test CoverageUnit tests were added for the new shared helper and for the component/static-file path handling, including regression coverage that ensures Backwards CompatibilityPaths containing def build_safe_abspath(component_root: str, relative_url_path: str) -> str | None:
r"""Build an absolute path inside ``component_root`` if safe.
...
if is_unsafe_path_pattern(relative_url_path):
return None
...Security & RiskSecurity posture is improved: SSRF/UNC path resolution is blocked before any filesystem operations, and explicit tests guard against regressions. No new security risks identified. Recommendations
VerdictAPPROVED: Security hardening is solid with good unit coverage and no functional regressions observed. This is an automated AI review using |
7e8adb2 to
29ac34d
Compare
lib/streamlit/web/server/starlette/starlette_path_security_middleware.py
Show resolved
Hide resolved
42e03e3 to
fea4030
Compare
Add path validation before os.path.realpath() calls to prevent Windows UNC paths from triggering SMB connections, which could enable SSRF attacks and NTLM hash disclosure. Changes: - Add _is_unsafe_path() helper to detect dangerous path patterns: - UNC paths (\\server\share, //server/share) - Windows drive letters (C:\, d:/) - Absolute paths (/etc/passwd, \rooted) - Path traversal (../ segments) - Null byte injection - Call validation before any realpath() in build_safe_abspath() - Add comprehensive tests for all unsafe path patterns This fix protects all 5 endpoints using build_safe_abspath(): - ComponentRequestHandler.get() - BidiComponentRequestHandler.get() - _component_endpoint() - _bidi_component_endpoint() - _app_static_endpoint()
Address reviewer feedback: use consistent 400 Bad Request for all malicious path requests instead of differentiating between 400 and 403. This makes error responses more opaque to attackers by not revealing how far their request progressed.
Use string.ascii_letters instead of str.isalpha() to detect Windows drive paths, avoiding false positives on valid POSIX filenames like 'Å:foo'. Resolves comment 1
…tions Change error from 'Absolute paths are not allowed' to 'Unsafe paths are not allowed' to accurately describe rejections for null bytes, UNC paths, etc. Resolves comment 2
Update Tornado component handlers to return 400 instead of 403 for unsafe paths, matching Starlette behavior for consistent opacity across servers. Resolves comment 3
a0aa4e1 to
2af08ad
Compare
sfc-gh-bnisco
left a comment
There was a problem hiding this comment.
Thanks for the iterations on this 👍
…handling (#13733) ## Describe your changes Added centralized path security validation to prevent Server-Side Request Forgery (SSRF) and path traversal vulnerabilities. The changes include: 1. Created a new `path_security.py` module with `is_unsafe_path_pattern()` function that detects potentially dangerous paths: - UNC paths (Windows network shares) - Absolute paths (Windows drive letters or root-based paths) - Path traversal attempts using `..` - Null byte injection attempts - Windows special path prefixes 2. Added a new `PathSecurityMiddleware` for Starlette that blocks unsafe paths at the HTTP layer before any filesystem operations. 3. Updated component path handling to validate paths BEFORE calling `os.path.realpath()`, preventing Windows from triggering SMB connections to attacker-controlled servers. 4. Modified `AppStaticFileHandler` to check for unsafe paths before filesystem operations. 5. Standardized security responses across the codebase (400 Bad Request for malicious paths). ## Testing Plan Added comprehensive test cases covering: - Detection of various unsafe path patterns - Validation of UNC paths and Windows drive letters - Handling of URL-decoded paths - Null byte injection attempts - Windows special path prefixes - Mixed path separator handling - Verification that legitimate paths still work correctly - Middleware positioning and integration with the request pipeline - Proper handling of WebSocket connections The tests verify both the new security functions and their integration across different parts of the codebase. --- **Contribution License Agreement** By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.
The path security middleware added in #13733 intercepts double-slash paths earlier in the request pipeline and returns 400 Bad Request instead of the previous 403 Forbidden from the route handler.
…do and Starlette (#13822) ## Summary - Added `UnsafePathBlockHandler` to the Tornado server that blocks double-slash paths with `400 Bad Request`, matching the Starlette `PathSecurityMiddleware` behavior - Updated the E2E test `test_double_slash_not_redirected_to_external` to expect `400` instead of `403` - Previously, the Starlette middleware (from #13733) returned 400 while Tornado relied on its built-in handling which returned 403, causing the test to fail depending on which server backend was used ### Files changed: - `lib/streamlit/web/server/routes.py` — Added `UnsafePathBlockHandler` class - `lib/streamlit/web/server/server.py` — Registered the handler as the first route - `e2e_playwright/web_server_test.py` — Updated test to expect 400 ## Test plan - [ ] `web_server_test.py::test_double_slash_not_redirected_to_external` passes for both Tornado and Starlette E2E test suites

Describe your changes
Added centralized path security validation to prevent Server-Side Request Forgery (SSRF) and path traversal vulnerabilities. The changes include:
Created a new
path_security.pymodule withis_unsafe_path_pattern()function that detects potentially dangerous paths:..Added a new
PathSecurityMiddlewarefor Starlette that blocks unsafe paths at the HTTP layer before any filesystem operations.Updated component path handling to validate paths BEFORE calling
os.path.realpath(), preventing Windows from triggering SMB connections to attacker-controlled servers.Modified
AppStaticFileHandlerto check for unsafe paths before filesystem operations.Standardized security responses across the codebase (400 Bad Request for malicious paths).
Testing Plan
Added comprehensive test cases covering:
The tests verify both the new security functions and their integration across different parts of the codebase.
Contribution License Agreement
By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.