fix(security): SSRF-guard save_url_video redirects - #70349
Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for covering the currently unguarded video delivery-URL path: current main still calls raw requests.get() in agent/video_gen_provider.py:274.
Problems
agent/video_gen_provider.py:291still usesrequests.get()after a DNS preflight.tools/url_safety.py:15-21documents that this leaves a DNS-rebinding TOCTOU window; direct host-side fetches needcreate_ssrf_safe_client()for connect-time validation.agent/video_gen_provider.py:294only handles a redirect whenLocationis present. A 3xx response without that header falls through toresponse.raise_for_status()and then the body-write path at lines 312-345 instead of failing closed.
Suggested changes
- Use
create_ssrf_safe_client(follow_redirects=False)with the explicit per-hop validation loop. - Explicitly reject every 3xx response lacking
Location, and cover it with a regression test plus a real local redirect-chain test.
Automated hermes-sweeper review.
| _max_redirects = 10 | ||
| response = None | ||
| for _hop in range(_max_redirects + 1): | ||
| response = requests.get( |
There was a problem hiding this comment.
is_safe_url() is only a preflight DNS check; this raw requests.get() resolves and connects independently. tools/url_safety.py:15-21 documents this DNS-rebinding TOCTOU and provides create_ssrf_safe_client() for connect-time validation. Please use that client here.
| response = requests.get( | ||
| current_url, timeout=timeout, stream=True, allow_redirects=False | ||
| ) | ||
| if response.is_redirect and response.headers.get("Location"): |
There was a problem hiding this comment.
Please detect every 3xx response explicitly and reject it when Location is absent. This condition treats a malformed 3xx-without-Location response as final, so it reaches raise_for_status() and then the download body path instead of failing closed.
|
suggesting changes The redirect checks prevent literal private and metadata URLs, but DNS rebinding can bypass them. A provider-controlled delivery hostname can resolve to a public address during validation and then resolve to an internal address when the download connects, allowing SSRF. Route every hop through a connect-time SSRF-safe transport (or equivalent DNS pinning), preserve the request hostname for Host/SNI, keep automatic redirects disabled with per-hop checks, and add a regression test that changes DNS between validation and connection and confirms that no private connection occurs. Security evidence:
Review setup: I reviewed a run-owned local rebase or patch replay against current GitHub Not checked:
Signed: GPT-5.6-luna-max in Codex |
fix(security): SSRF-guard save_url_video redirects
|
e7329a7 to
d55c0f3
Compare
|
Refreshed against the fixed official main ancestor |
## Summary - Apply `is_safe_url` and manual redirect re-validation to `save_url_video` (sibling of the image path). - Prevent cloud-metadata / private-target pivots via redirected CDN URLs when downloading generated video assets. - Add focused regression tests. ## Salvage / credit Sibling coverage for the incomplete image-side work tracked around NousResearch#44743 / NousResearch#44728 (video download path was still unprotected).
d55c0f3 to
f7c8614
Compare
Summary
is_safe_urland manual redirect re-validation tosave_url_video(sibling of the image path).Salvage / credit
Sibling coverage for the incomplete image-side work tracked around #44743 / #44728 (video download path was still unprotected).
Test plan
pytest tests/agent/test_save_url_video_ssrf.py -q