security: address CodeRabbit review feedback on GHSA-779p tests

- 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.
This commit is contained in:
Matt Miller 2026-07-02 20:08:13 -07:00
parent e4eb7f2698
commit 5611d1c9b6
2 changed files with 19 additions and 8 deletions

View File

@ -87,8 +87,14 @@ def test_is_within_directory_symlink_escape(sandbox):
f.write("top secret")
# Plant a symlink inside base that points at the outside directory.
# symlink creation can require elevated privileges / Developer Mode on
# Windows, so skip cleanly where it isn't available (same guard as the
# sibling test in test_ghsa_779p_02_preview_traversal.py).
link = os.path.join(base, "escape_link")
os.symlink(outside, link)
try:
os.symlink(outside, link)
except (OSError, NotImplementedError):
pytest.skip("symlinks not supported on this platform/filesystem")
# Accessing the secret "through" the in-base symlink must be rejected.
target_via_link = os.path.join(link, "secret.txt")

View File

@ -5,13 +5,18 @@ blocklist covered text/html, text/javascript, etc. but was missing
image/svg+xml, so an uploaded SVG carrying an inline <script> was served as
image/svg+xml and executed in the page origin when rendered.
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
full PromptServer/aiohttp app and its global side effects), so these tests pin
the *data* that drives the closure: folder_paths.DANGEROUS_CONTENT_TYPES.
The /view forced-download decision lives in the view_image closure registered by
server.PromptServer.add_routes (server.py ~line 596), which calls
`folder_paths.is_dangerous_content_type(content_type)` a normalising check that
strips charset/boundary parameters and casing and folds in the whole */xml and
*+xml dialect family rather than a bypassable raw
`content_type in folder_paths.DANGEROUS_CONTENT_TYPES` membership test. On a match
it 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 full PromptServer/aiohttp app and its global side
effects), so these tests pin the underlying dangerous-content data
(folder_paths.DANGEROUS_CONTENT_TYPES) and the normalising is_dangerous_content_type()
helper that the closure actually calls.
The end-to-end /view assertion (upload an SVG, GET /view, confirm the response
is not served as image/svg+xml) lives in the live POC at