What happened?
The generated Python's _fetch_remote_url (PythonCodegenBase.scala ~L707-746 in common/workflow-operator/.../huggingFace/codegen/) hardens remote fetches: https-only, resolves the host and rejects private/loopback/link-local/reserved IPs, and caps response size. It then calls requests.get(url, ...) with the default allow_redirects=True, so only the original URL is validated. A redirect can point anywhere: a 302 to http://169.254.169.254/... (cloud metadata) or any internal service is followed without re-running either the private-IP check or the https-only rule (requests follows cross-scheme redirects on GET).
All remote fetches in the operator flow through this helper: user-provided image/audio URLs (_read_image_input, _read_audio_input, column values via _read_binary_value) and media URLs returned by inference providers (_url_to_data_url). A malicious workflow input or a compromised provider response can therefore make the worker fetch internal endpoints and exfiltrate the content via the result column.
The existing spec test ("harden remote URL fetches against SSRF") asserts on generated code text only and doesn't cover redirect behavior.
Fix: pass allow_redirects=False and either fail on 3xx or follow a bounded number of hops manually, re-validating scheme + resolved IPs on every hop before requesting it. Pin the behavior in HuggingFaceInferenceOpDescSpec.scala.
How to reproduce?
- Run an image/audio task with an input URL pointing at a server you control that 302-redirects to
http://127.0.0.1:<port>/... or an internal address.
- The worker follows the redirect and the fetched internal content lands in the result column; the IP/scheme checks never run against the redirect target.
Version/Branch
1.3.0-incubating-SNAPSHOT (main)
Commit Hash (Optional)
No response
What browsers are you seeing the problem on?
No response
Relevant log output
What happened?
The generated Python's
_fetch_remote_url(PythonCodegenBase.scala~L707-746 incommon/workflow-operator/.../huggingFace/codegen/) hardens remote fetches: https-only, resolves the host and rejects private/loopback/link-local/reserved IPs, and caps response size. It then callsrequests.get(url, ...)with the defaultallow_redirects=True, so only the original URL is validated. A redirect can point anywhere: a 302 tohttp://169.254.169.254/...(cloud metadata) or any internal service is followed without re-running either the private-IP check or the https-only rule (requests follows cross-scheme redirects on GET).All remote fetches in the operator flow through this helper: user-provided image/audio URLs (
_read_image_input,_read_audio_input, column values via_read_binary_value) and media URLs returned by inference providers (_url_to_data_url). A malicious workflow input or a compromised provider response can therefore make the worker fetch internal endpoints and exfiltrate the content via the result column.The existing spec test ("harden remote URL fetches against SSRF") asserts on generated code text only and doesn't cover redirect behavior.
Fix: pass
allow_redirects=Falseand either fail on 3xx or follow a bounded number of hops manually, re-validating scheme + resolved IPs on every hop before requesting it. Pin the behavior inHuggingFaceInferenceOpDescSpec.scala.How to reproduce?
http://127.0.0.1:<port>/...or an internal address.Version/Branch
1.3.0-incubating-SNAPSHOT (main)
Commit Hash (Optional)
No response
What browsers are you seeing the problem on?
No response
Relevant log output