CVE-2026-54695
Pipecat: Telephony WebSocket `/ws` Unauthenticated Call-Control Abuse via Attacker-Supplied Call SID
Pipecat is an open-source Python framework for building real-time voice and multimodal conversational agents. Prior to 1.4.0, the pipecat development runner registers a /ws WebSocket endpoint for telephony testing that accepts connections without authentication, reads an attacker-supplied callSid from a Twilio stream-start handshake in src/pipecat/runner/utils.py, and passes it to TwilioFrameSerializer so the server can issue an authenticated Twilio REST API hang-up request with the server operator's credentials; equivalent unauthenticated call-control sinks exist for Telnyx and Plivo. This issue is fixed in version 1.4.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- High
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- Low
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
7.5
Pipecat: Telephony WebSocket `/ws` Unauthenticated Call-Control Abuse via Attacker-Supplied Call SID
Pipecat is an open-source Python framework for building real-time voice and multimodal conversational agents. Prior to 1.4.0, the pipecat development runner registers a /ws WebSocket endpoint for telephony testing that accepts connections without authentication, reads an attacker-supplied callSid from a Twilio stream-start handshake in src/pipecat/runner/utils.py, and passes it to TwilioFrameSerializer so the server can issue an authenticated Twilio REST API hang-up request with the server operator's credentials; equivalent unauthenticated call-control sinks exist for Telnyx and Plivo. This issue is fixed in version 1.4.0.
- Record
CVE-2026-54695- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:L/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
EUVDEUVD-2026-42673
7.5
Pipecat is an open-source Python framework for building real-time voice and multimodal conversational agents. Prior to 1.4.0, the pipecat development runner registers a /ws WebSocket endpoint for telephony testing that accepts connections without authentication, reads an attacker-supplied callSid from a Twilio stream-start handshake in src/pipecat/runner/utils.py, and passes it to TwilioFrameSerializer so the server can issue an authenticated Twilio REST API hang-up request with the server operator's credentials; equivalent unauthenticated call-control sinks exist for Telnyx and Plivo. This issue is fixed in version 1.4.0.
- Record
EUVD-2026-42673- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:L/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-j8cv-x86q-rj85
7.5
Pipecat: Telephony WebSocket `/ws` Unauthenticated Call-Control Abuse via Attacker-Supplied Call SID
Development Runner Telephony WebSocket /ws Unauthenticated Call-Control Abuse via Attacker-Supplied Call SID
Summary
The pipecat development runner registers a /ws WebSocket endpoint for telephony testing that accepts connections without any authentication. An unauthenticated remote attacker who can reach an exposed runner endpoint can connect to this endpoint, send a crafted Twilio handshake message containing an attacker-supplied callSid, and cause the server to issue an authenticated Twilio REST API hang-up request against that call SID using the server operator's own credentials. This may allow the attacker to forcibly terminate an active call on the victim's Twilio account if the attacker knows or obtains a valid call SID for that account. Equivalent unauthenticated call-control sinks exist for Telnyx and Plivo. Maintainers are evaluating the final CVSS 3.1 score.
Details
The pipecat development runner registers a WebSocket route at /ws (src/pipecat/runner/run.py:1116). When a client connects, the server immediately accepts the connection without performing any authentication or signature verification (run.py:1119):
await websocket.accept() # run.py:1119 — no auth check before this point
After acceptance, the server reads the Twilio WebSocket stream-start handshake and extracts the callSid field verbatim from the attacker-controlled JSON payload (src/pipecat/runner/utils.py:223):
call_id: start_data.get("callSid") # utils.py:223 — tainted, attacker-supplied
The tainted call_id is then passed directly into TwilioFrameSerializer alongside the server's own Twilio account credentials, which are read from environment variables (src/pipecat/runner/utils.py:513-517):
TwilioFrameSerializer(
stream_sid=stream_id,
call_sid=call_id, # TAINTED
account_sid=os.getenv("TWILIO_ACCOUNT_SID"), # server credential
auth_token=os.getenv("TWILIO_AUTH_TOKEN"), # server credential
)
TwilioFrameSerializer has auto_hang_up defaulting to True (src/pipecat/serializers/twilio.py:56). When the pipeline terminates and serializes an EndFrame or CancelFrame, _hang_up_call() is triggered (twilio.py:141-147). This method constructs a Twilio REST API URL containing the attacker-supplied call_sid and POSTs to it using the server's own credentials (twilio.py:196, twilio.py:206):
POST https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Calls/{attacker_call_sid}.json
Authorization: Basic <base64(account_sid:auth_token)>
Body: Status=completed
The same unauthenticated call-control pattern exists for Telnyx (src/pipecat/serializers/telnyx.py:188, :195) and Plivo (src/pipecat/serializers/plivo.py:180, :187).
Although the runner defaults to localhost and is documented as a development runner, its telephony mode is commonly used with a public proxy hostname so that telephony providers can connect inbound calls. If the development runner is exposed to untrusted networks while configured with Twilio, Telnyx, or Plivo credentials, this becomes a realistic network-reachable attack surface.
PoC
Prerequisites
- Docker (for building the isolated PoC image)
- A clone of the pipecat repository at commit
b982b45a7ae1e5ee99e4390ad5a116cdd9b4a8e2placed at<context_root>/repo/ - The files
vuln-001/Dockerfileandvuln-001/poc.pypresent under<context_root>/
Step 1 — Build the Docker image
docker build \
-f vuln-001/Dockerfile \
-t vuln001-poc \
reports/pypiAi_247_pipecat-ai__pipecat
The Dockerfile installs pipecat from the local repository clone, generates a self-signed TLS CA and server certificate for api.twilio.com, and registers that CA in the system trust store so that pipecat's aiohttp-based HTTP client accepts the mock server certificate.
Step 2 — Run the PoC
docker run --rm \
--add-host api.twilio.com:127.0.0.1 \
…
- Record
GHSA-j8cv-x86q-rj85- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:L/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
NVD
7.5
Pipecat is an open-source Python framework for building real-time voice and multimodal conversational agents. Prior to 1.4.0, the pipecat development runner registers a /ws WebSocket endpoint for telephony testing that accepts connections without authentication, reads an attacker-supplied callSid from a Twilio stream-start handshake in src/pipecat/runner/utils.py, and passes it to TwilioFrameSerializer so the server can issue an authenticated Twilio REST API hang-up request with the server operator's credentials; equivalent unauthenticated call-control sinks exist for Telnyx and Plivo. This issue is fixed in version 1.4.0.
- Record
CVE-2026-54695- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:L/A:H - CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
OSV
7.5
Pipecat: Telephony WebSocket `/ws` Unauthenticated Call-Control Abuse via Attacker-Supplied Call SID
Pipecat is an open-source Python framework for building real-time voice and multimodal conversational agents. Prior to 1.4.0, the pipecat development runner registers a /ws WebSocket endpoint for telephony testing that accepts connections without authentication, reads an attacker-supplied callSid from a Twilio stream-start handshake in src/pipecat/runner/utils.py, and passes it to TwilioFrameSerializer so the server can issue an authenticated Twilio REST API hang-up request with the server operator's credentials; equivalent unauthenticated call-control sinks exist for Telnyx and Plivo. This issue is fixed in version 1.4.0.
- Record
CVE-2026-54695- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:L/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
OSVGHSA-j8cv-x86q-rj85
7.5
Pipecat: Telephony WebSocket `/ws` Unauthenticated Call-Control Abuse via Attacker-Supplied Call SID
Development Runner Telephony WebSocket /ws Unauthenticated Call-Control Abuse via Attacker-Supplied Call SID
Summary
The pipecat development runner registers a /ws WebSocket endpoint for telephony testing that accepts connections without any authentication. An unauthenticated remote attacker who can reach an exposed runner endpoint can connect to this endpoint, send a crafted Twilio handshake message containing an attacker-supplied callSid, and cause the server to issue an authenticated Twilio REST API hang-up request against that call SID using the server operator's own credentials. This may allow the attacker to forcibly terminate an active call on the victim's Twilio account if the attacker knows or obtains a valid call SID for that account. Equivalent unauthenticated call-control sinks exist for Telnyx and Plivo. Maintainers are evaluating the final CVSS 3.1 score.
Details
The pipecat development runner registers a WebSocket route at /ws (src/pipecat/runner/run.py:1116). When a client connects, the server immediately accepts the connection without performing any authentication or signature verification (run.py:1119):
await websocket.accept() # run.py:1119 — no auth check before this point
After acceptance, the server reads the Twilio WebSocket stream-start handshake and extracts the callSid field verbatim from the attacker-controlled JSON payload (src/pipecat/runner/utils.py:223):
call_id: start_data.get("callSid") # utils.py:223 — tainted, attacker-supplied
The tainted call_id is then passed directly into TwilioFrameSerializer alongside the server's own Twilio account credentials, which are read from environment variables (src/pipecat/runner/utils.py:513-517):
TwilioFrameSerializer(
stream_sid=stream_id,
call_sid=call_id, # TAINTED
account_sid=os.getenv("TWILIO_ACCOUNT_SID"), # server credential
auth_token=os.getenv("TWILIO_AUTH_TOKEN"), # server credential
)
TwilioFrameSerializer has auto_hang_up defaulting to True (src/pipecat/serializers/twilio.py:56). When the pipeline terminates and serializes an EndFrame or CancelFrame, _hang_up_call() is triggered (twilio.py:141-147). This method constructs a Twilio REST API URL containing the attacker-supplied call_sid and POSTs to it using the server's own credentials (twilio.py:196, twilio.py:206):
POST https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Calls/{attacker_call_sid}.json
Authorization: Basic <base64(account_sid:auth_token)>
Body: Status=completed
The same unauthenticated call-control pattern exists for Telnyx (src/pipecat/serializers/telnyx.py:188, :195) and Plivo (src/pipecat/serializers/plivo.py:180, :187).
Although the runner defaults to localhost and is documented as a development runner, its telephony mode is commonly used with a public proxy hostname so that telephony providers can connect inbound calls. If the development runner is exposed to untrusted networks while configured with Twilio, Telnyx, or Plivo credentials, this becomes a realistic network-reachable attack surface.
PoC
Prerequisites
- Docker (for building the isolated PoC image)
- A clone of the pipecat repository at commit
b982b45a7ae1e5ee99e4390ad5a116cdd9b4a8e2placed at<context_root>/repo/ - The files
vuln-001/Dockerfileandvuln-001/poc.pypresent under<context_root>/
Step 1 — Build the Docker image
docker build \
-f vuln-001/Dockerfile \
-t vuln001-poc \
reports/pypiAi_247_pipecat-ai__pipecat
The Dockerfile installs pipecat from the local repository clone, generates a self-signed TLS CA and server certificate for api.twilio.com, and registers that CA in the system trust store so that pipecat's aiohttp-based HTTP client accepts the mock server certificate.
Step 2 — Run the PoC
docker run --rm \
--add-host api.twilio.com:127.0.0.1 \
…
- Record
GHSA-j8cv-x86q-rj85- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:L/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
OSVPYSEC-2026-2878
7.5
Pipecat: Telephony WebSocket `/ws` Unauthenticated Call-Control Abuse via Attacker-Supplied Call SID
Development Runner Telephony WebSocket /ws Unauthenticated Call-Control Abuse via Attacker-Supplied Call SID
Summary
The pipecat development runner registers a /ws WebSocket endpoint for telephony testing that accepts connections without any authentication. An unauthenticated remote attacker who can reach an exposed runner endpoint can connect to this endpoint, send a crafted Twilio handshake message containing an attacker-supplied callSid, and cause the server to issue an authenticated Twilio REST API hang-up request against that call SID using the server operator's own credentials. This may allow the attacker to forcibly terminate an active call on the victim's Twilio account if the attacker knows or obtains a valid call SID for that account. Equivalent unauthenticated call-control sinks exist for Telnyx and Plivo. Maintainers are evaluating the final CVSS 3.1 score.
Details
The pipecat development runner registers a WebSocket route at /ws (src/pipecat/runner/run.py:1116). When a client connects, the server immediately accepts the connection without performing any authentication or signature verification (run.py:1119):
await websocket.accept() # run.py:1119 — no auth check before this point
After acceptance, the server reads the Twilio WebSocket stream-start handshake and extracts the callSid field verbatim from the attacker-controlled JSON payload (src/pipecat/runner/utils.py:223):
call_id: start_data.get("callSid") # utils.py:223 — tainted, attacker-supplied
The tainted call_id is then passed directly into TwilioFrameSerializer alongside the server's own Twilio account credentials, which are read from environment variables (src/pipecat/runner/utils.py:513-517):
TwilioFrameSerializer(
stream_sid=stream_id,
call_sid=call_id, # TAINTED
account_sid=os.getenv("TWILIO_ACCOUNT_SID"), # server credential
auth_token=os.getenv("TWILIO_AUTH_TOKEN"), # server credential
)
TwilioFrameSerializer has auto_hang_up defaulting to True (src/pipecat/serializers/twilio.py:56). When the pipeline terminates and serializes an EndFrame or CancelFrame, _hang_up_call() is triggered (twilio.py:141-147). This method constructs a Twilio REST API URL containing the attacker-supplied call_sid and POSTs to it using the server's own credentials (twilio.py:196, twilio.py:206):
POST https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Calls/{attacker_call_sid}.json
Authorization: Basic <base64(account_sid:auth_token)>
Body: Status=completed
The same unauthenticated call-control pattern exists for Telnyx (src/pipecat/serializers/telnyx.py:188, :195) and Plivo (src/pipecat/serializers/plivo.py:180, :187).
Although the runner defaults to localhost and is documented as a development runner, its telephony mode is commonly used with a public proxy hostname so that telephony providers can connect inbound calls. If the development runner is exposed to untrusted networks while configured with Twilio, Telnyx, or Plivo credentials, this becomes a realistic network-reachable attack surface.
PoC
Prerequisites
- Docker (for building the isolated PoC image)
- A clone of the pipecat repository at commit
b982b45a7ae1e5ee99e4390ad5a116cdd9b4a8e2placed at<context_root>/repo/ - The files
vuln-001/Dockerfileandvuln-001/poc.pypresent under<context_root>/
Step 1 — Build the Docker image
docker build \
-f vuln-001/Dockerfile \
-t vuln001-poc \
reports/pypiAi_247_pipecat-ai__pipecat
The Dockerfile installs pipecat from the local repository clone, generates a self-signed TLS CA and server certificate for api.twilio.com, and registers that CA in the system trust store so that pipecat's aiohttp-based HTTP client accepts the mock server certificate.
Step 2 — Run the PoC
docker run --rm \
--add-host api.twilio.com:127.0.0.1 \
…
- Record
PYSEC-2026-2878- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:L/A:H - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
pipecat-aiPyPI |
0.0.77 up to 1.4.0 | 1.4.0 |
pipecat-aiPyPI |
0.0.77 up to 1.4.0, plus listed versions 0.0.1000.0.1010.0.1020.0.1030.0.104 Show 31 moreShow less0.0.1050.0.1060.0.1070.0.1080.0.780.0.790.0.800.0.810.0.820.0.830.0.840.0.850.0.860.0.870.0.880.0.890.0.900.0.910.0.920.0.930.0.940.0.950.0.960.0.970.0.980.0.991.0.01.1.01.2.01.2.11.3.0 |
1.4.0 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-54695 is a high vulnerability (CVSS 7.5) in Pipecat, published June 18, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.56%, the 47th percentile. Fixed in pipecat-ai 1.4.0.
References
github.com/pipecat-ai/pipecat/security/advisories/GHSA-j8cv-x86q-rj85
github.com/pipecat-ai/pipecat/pull/4660
github.com/pipecat-ai/pipecat/commit/3032da53434c5ef01d368654b3551cf21c50dec9
github.com/pipecat-ai/pipecat/commit/88440676996e5e548e1aecea5d565e1c48ccf6fa
github.com/pipecat-ai/pipecat/releases/tag/v1.4.0
github.com/advisories/GHSA-j8cv-x86q-rj85
Left out here: the rest of 3 source descriptions. The JSON record has them.