security: fix four vulnerabilities (GHSA-779p-m5rp-r4h4)#14734
Conversation
📝 WalkthroughWalkthroughThis PR addresses GHSA-779p-m5rp-r4h4, fixing content-type sniffing/stored-XSS, path traversal, and CSRF issues. It adds Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Endpoint
participant FolderPaths
Client->>Endpoint: request file/asset with content-type
Endpoint->>FolderPaths: is_dangerous_content_type(content_type)
FolderPaths-->>Endpoint: True/False
alt dangerous
Endpoint-->>Client: octet-stream, attachment, nosniff
else safe
Endpoint-->>Client: original content-type
end
Related PRs: None specified. Suggested labels: security, needs-review Suggested reviewers: None specified. Poem 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
- CVE-2026-56670: force download of SVG/XML responses on /view to prevent stored XSS
- CVE-2026-56671: contain /experiment/models/preview reads within the model folder
- CVE-2026-56672: stop inline rendering of uploaded /userdata/{file} content
- CVE-2026-56673: prevent path traversal in get_annotated_filepath (LoadImage /prompt input)
- CVE-2026-56674: reject opaque/null Origin to close the CSRF middleware bypass
Adds regression tests under tests-unit/security_test/ covering all five.
926c169 to
ae4fcaa
Compare
There was a problem hiding this comment.
🔍 Cursor Review — Consolidated panel
Triggered by @mattmillerai.
Found 8 finding(s).
| Severity | Count |
|---|---|
| 🟠 High | 1 |
| 🟡 Medium | 4 |
| 🟢 Low | 2 |
| ⚪ Nit | 1 |
Panel: 8/8 reviewers contributed findings.
- Fix Windows CI failure in test_get_annotated_filepath: compare against os.path.abspath(...) to match the intentional abspath normalization added by the traversal hardening (abspath prepends the drive letter on Windows). - origin_check: narrow the bare `except:` in is_loopback() to ValueError so genuine interrupts aren't swallowed (review nit). - origin_check: guard .port access in is_cross_origin_forbidden() so a malformed/out-of-range port (e.g. Origin: http://127.0.0.1:99999) fails closed with a 403 instead of surfacing an uncaught 500 in the middleware. - server /view: escape backslash/quote in the Content-Disposition filename (RFC 6266 quoted-string) so a filename containing a double quote can't malform the response header.
8a275f1 to
e4eb7f2
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
tests-unit/security_test/test_ghsa_779p_05_dangerous_content_types.py (1)
8-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDocstring describes a stale/bypassable mechanism.
This describes the
/viewclosure as checkingcontent_type in folder_paths.DANGEROUS_CONTENT_TYPES(raw set membership), but the actual handler (perserver.py'sview_image) callsfolder_paths.is_dangerous_content_type(content_type), which normalizes casing/params/XML dialects — that's the whole point of the hardening this test file documents. Worth correcting so future readers don't think the raw membership check (the bypassable one) is what's actually gating/view.✏️ Suggested docstring fix
-The /view forced-download decision lives in a closure inside -server.PromptServer.add_routes (server.py ~line 624), which checks -`content_type in folder_paths.DANGEROUS_CONTENT_TYPES` and, on a match, rewrites -the response to application/octet-stream with a Content-Disposition: attachment -header. server.py cannot be imported in a unit test (importing it spins up the +The /view forced-download decision lives in a closure inside +server.PromptServer.add_routes (server.py ~line 624), which checks +`folder_paths.is_dangerous_content_type(content_type)` and, on a match, rewrites +the response to application/octet-stream with a Content-Disposition: attachment +header. server.py cannot be imported in a unit test (importing it spins up the🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests-unit/security_test/test_ghsa_779p_05_dangerous_content_types.py` around lines 8 - 14, Update the test docstring/comments in the security test to describe the actual /view gating logic, not the stale raw membership check. Reference the view handler path via server.PromptServer.add_routes and the view_image behavior, and make it clear that the closure uses folder_paths.is_dangerous_content_type(...) rather than direct content_type in folder_paths.DANGEROUS_CONTENT_TYPES membership. Keep the explanation aligned with the hardened, normalized check so readers understand the test is pinning the underlying dangerous-content data, not the bypassable raw set lookup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests-unit/security_test/test_ghsa_779p_03_annotated_traversal.py`:
- Around line 72-95: The symlink-escape test is not safe to run unconditionally
on Windows because os.symlink may require elevated privileges or Developer Mode.
Update test_is_within_directory_symlink_escape to add the same
platform/permission guard used by the other symlink tests, so the symlink setup
and assertion are skipped on Windows CI when symlinks are unavailable.
---
Nitpick comments:
In `@tests-unit/security_test/test_ghsa_779p_05_dangerous_content_types.py`:
- Around line 8-14: Update the test docstring/comments in the security test to
describe the actual /view gating logic, not the stale raw membership check.
Reference the view handler path via server.PromptServer.add_routes and the
view_image behavior, and make it clear that the closure uses
folder_paths.is_dangerous_content_type(...) rather than direct content_type in
folder_paths.DANGEROUS_CONTENT_TYPES membership. Keep the explanation aligned
with the hardened, normalized check so readers understand the test is pinning
the underlying dangerous-content data, not the bypassable raw set lookup.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: f3d7af24-b907-4bbc-ab95-78b13db88f98
📥 Commits
Reviewing files that changed from the base of the PR and between 35c1470 and 8a275f1a10a32254d1c2ae8ecd4f3980f77f3bf9.
📒 Files selected for processing (14)
app/assets/api/routes.pyapp/model_manager.pyapp/user_manager.pyfolder_paths.pyserver.pytests-unit/assets_test/test_downloads.pytests-unit/comfy_test/folder_path_test.pytests-unit/security_test/__init__.pytests-unit/security_test/test_ghsa_779p_01_origin_csrf.pytests-unit/security_test/test_ghsa_779p_02_preview_traversal.pytests-unit/security_test/test_ghsa_779p_03_annotated_traversal.pytests-unit/security_test/test_ghsa_779p_04_userdata_xss.pytests-unit/security_test/test_ghsa_779p_05_dangerous_content_types.pyutils/origin_check.py
- test #3: guard the symlink-escape test with a try/except skip so it no longer errors on Windows CI where os.symlink needs elevated privileges / Developer Mode (mirrors the guard in the sibling test #2). - test #5: refresh the stale module docstring to describe the actual /view gating (view_image closure calling folder_paths.is_dangerous_content_type, the normalising check) instead of the bypassable raw set-membership test.
29cd1a0 to
5611d1c
Compare
Per maintainer review, the reported CSRF is already mitigated by the pre-existing Sec-Fetch-Site: cross-site check for current browsers, and the null-origin rejection risked breaking legitimate sandboxed-iframe embeds. Restores origin_only_middleware and is_loopback in server.py to their prior state (the Sec-Fetch-Site check is retained) and removes utils/origin_check.py and its regression test. The other four GHSA-779p fixes are unaffected.
Coordinated-disclosure fixes for GHSA-779p-m5rp-r4h4 (reported via CISA VINCE).
CVEs fixed
/view/experiment/models/preview/userdata/{file}content-type sniffingLoadImagevia/promptget_annotated_filepathNot included
Sec-Fetch-Site: cross-sitecheck on current browsers. The null-origin change was reverted to avoid breaking legitimate sandboxed-iframe embeds. This CVE is being disputed with CISA rather than fixed.Notes
tests-unit/security_test/(four findings).