AI/ML ingestion boundaries: URL-partitioning SSRF, SSRF redirect bypass, checkpoint deserialization, and non-superuser LLM-config overwrite (GHSA)¶
Source: hourly offensive-security scan, 2026-09-03/04 GitHub advisory updated wave. Durable because these five records span the two most reusable AI/ML operator axes this wiki already carries — ingest-then-fetch SSRF and trusted-artifact deserialization/RCE — plus a new AI-platform global-config authorization axis (Cognee). Each is a distinct trust boundary, but the audit pattern is the same: untrusted material (a URL, a checkpoint file, a config write) crosses from "input" to "server-side authority" without the expected gate.
Primary entries:
| GHSA | Product | Boundary | Defect | Severity |
|---|---|---|---|---|
| GHSA-4MVJ-M6J5-PMF7 / CVE-2026-71428 | unstructured (pip >= 0.4.7, < 0.24.0) | URL-based partitioning SSRF | the partitioner fetches caller-supplied URLs server-side without an allow/deny network gate | critical 9.3 |
| GHSA-MR4R-HCGX-8P4H / CVE-2026-62240 | crewai-tools (pip < 1.15.1) | Tool fetch SSRF redirect bypass | an initial-URL SSRF check is applied but the redirect response follows to an internal/synthetic-denied host | high 7.4 |
| GHSA-QQMF-GPG7-G8GW / CVE-2026-58659 | lightning / PyTorch Lightning (pip < 2022.6.15 line) | Checkpoint _instantiator hyperparameters | loading a checkpoint invokes user-supplied _instantiator callables → arbitrary code execution | high 7.8 |
| GHSA-997V-R4V7-9F3G / CVE-2026-15529 | pyod (pip >= 3.5.0, < 3.6.2) | persistence.load deserialization order | untrusted artifacts are deserialized before validation, so a malicious pickle payload executes on load | medium 6.3 |
| GHSA-49F7-WHX5-4256 / CVE-2026-58473 | cognee (pip < 1.5.0) | Global LLM configuration authorization | a non-superuser can overwrite the platform-wide LLM configuration | critical 9.1 |
Authorized validation only
Keep proofs to disposable lab instances with synthetic checkpoints/URLs, owned no-content peers, and denied network/file/process sinks. Prove SSRF with an owned callback, not metadata or RFC1918 production hosts. Prove deserialization with an inert canary payload that writes one marker, not real data. Prove the Cognee config boundary with a synthetic non-superuser and a canary config value. Do not load untrusted model code on production workers, read real LLM keys, or mutate a live shared deployment.
Boundary map¶
| Product | Input | Trust break | Reusable check |
|---|---|---|---|
unstructured | URL passed to the partitioner | no server-side fetch gate | Partition a URL that points at an owned listener; record whether the server dialed it and whether a denied-destination URL is blocked. |
crewai-tools | Tool-fetch URL + redirect | check applied to hop 0, not the post-redirect host | Have an owned redirector 301 to a second owned "denied" listener; record the decision vs the final dial. |
lightning checkpoint | checkpoint file with _instantiator | checkpoint treated as trusted artifact | Load a synthetic checkpoint whose _instantiator is a marker callable; record whether it is invoked. |
pyod artifact | serialized artifact to persistence.load | deserialize-before-validate order | Feed a marker pickle that writes one file on __reduce__; record whether it runs before the validator. |
cognee | config-write request from non-superuser | role gate not applied to global LLM config | As a synthetic non-superuser, attempt one benign config change; record whether the global LLM config is written. |
Replayable validation boundaries¶
unstructured URL-partitioning SSRF¶
- Stand up a disposable
unstructured(vulnerable line>= 0.4.7, < 0.24.0) with network access limited to your owned listeners. - Run the URL-based partitioner against (a) an owned callback URL and (b) a synthetic denied destination (your "internal" listener). Record which are fetched and which are blocked.
- A positive is the server dialing a caller-supplied URL with no allow/deny gate. Keep it to the callback nonce; do not fetch metadata, cloud endpoints, or internal services.
crewai-tools SSRF redirect bypass¶
- Use two owned listeners: A (initial, allowed-looking) and B (synthetic "denied"/internal target).
- Configure A to 301-redirect to B. Drive the tool's fetch at A.
- A positive is the SSRF gate evaluating the initial URL but the request ultimately reaching B. Record the validated host, the redirect hop, and the final dialed host. Do not use uncontrolled public redirects or cloud metadata.
PyTorch Lightning checkpoint _instantiator RCE¶
- Build a minimal synthetic Lightning checkpoint whose hyperparameters contain an
_instantiatorfield naming a marker callable (a function whose only effect is to append a fixed line to a disposable log). - In a disposable training/inference process, load that checkpoint. Record whether the marker callable is invoked.
- Negative control: a checkpoint with no
_instantiator, and the patched build. Do not point_instantiatorat real credentials, model weights, or cloud config; the proof is "callable invoked on load," not data access.
pyod persistence.load deserialization-before-validation¶
- Create a marker artifact whose deserialization (
__reduce__or equivalent) writes one inert file to a disposable path. - Call
persistence.loadon it in a disposable process. Record whether the marker write occurs, and before any validator returns. - Negative control: the
>= 3.6.2build and a benign artifact. Do not exfiltrate or read real data; the proof is execution-order evidence.
Cognee non-superuser LLM-config overwrite¶
- Provision a disposable Cognee (
< 1.5.0) with one synthetic superuser and one synthetic non-superuser. - From the non-superuser session, attempt one benign LLM-config write (e.g. set a marker model id). Record whether the global LLM configuration changes.
- Negative control: the
>= 1.5.0build and the same request from a properly scoped role. Do not point the overwritten config at a real LLM provider key, external endpoint, or shared production deployment; the proof is the config write decision, not a live model call.
Durable operator value¶
- Ingest-then-fetch is the SSRF class. Any AI pipeline that accepts a URL and fetches it server-side (document partitioning, RAG ingestion, tool fetch) is an SSRF surface. The reusable check is: is there a server-side allow/deny network gate, and does it apply to the final resolved host, not just the first hop?
- Redirect hops defeat naive SSRF gates. A check that validates the requested URL but not the post-redirect destination is the
crewai-toolspattern. Audit every fetch for redirect-follow behavior. - Checkpoints and serialized artifacts are trusted artifacts. A
.ckpt/pickle that runs user-supplied callables on load is RCE-by-file. The reusable check is: does the loader invoke_instantiator/__reduce__before validation, and can a low-priv actor supply the file? - AI-platform global config is a privilege surface. Cognee's non-superuser LLM-config overwrite is the same family as model-loading RCE and vector-store tenant bypass — a config/model/identity write that should be role-gated. When auditing AI platforms, test every global config/model/LLM-key write for role enforcement.
- Report the trust break, not the CVE count. Each of the five is one narrow transition; frame each as input → authority crossing with the exact field, endpoint, and canary evidence.
Safety¶
- Owned listeners only for all SSRF legs; no metadata, no RFC1918 production, no uncontrolled public DNS/redirects.
- Marker-only deserialization proofs; no real secret/model/weight access.
- Synthetic roles and canary config for Cognee; no live LLM provider or shared-deployment mutation.
- Disposable instances throughout; coordinate with the asset owner for any non-lab target.
Source: hourly offensive-security scan, 2026-09-03/04. All 5 advisories tracked in the source index.