Skip to main content

Apify MCP Server CVE-2026-46341

MEDIUM
Improper Input Validation (CWE-20)
2026-05-19 https://github.com/apify/apify-mcp-server GHSA-jwp7-wg77-3w9v
6.1
CVSS 3.1 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
6.1 MEDIUM
AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

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

Lifecycle Timeline

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

DescriptionGitHub Advisory

Summary

The fetch-apify-docs tool validates URLs against a domain allowlist using String.startsWith() instead of proper URL hostname comparison. This allows bypass via attacker-controlled subdomains (e.g., https://docs.apify.com.evil.com/), enabling the tool to fetch and return arbitrary web content to the LLM.

Details

Vulnerable component

src/tools/common/fetch_apify_docs.ts, line 51:

typescript
const isAllowedDomain = ALLOWED_DOC_DOMAINS.some((domain) => url.startsWith(domain));

src/const.ts, lines 167-170:

typescript
export const ALLOWED_DOC_DOMAINS = [
    'https://docs.apify.com',
    'https://crawlee.dev',
] as const;
How the bypass works

String.startsWith('https://docs.apify.com') matches any string beginning with that prefix, including:

  • https://docs.apify.com.evil.com/payload - attacker-controlled subdomain
  • https://docs.apify.com@evil.com/payload - userinfo component in URL (browser behavior varies, but fetch() in Node.js may follow this)
  • https://docs.apify.com.evil.com:8080/path - custom port on attacker domain

All of these pass the startsWith check because they begin with the exact string https://docs.apify.com.

The fetched content is returned to the LLM

After the allowlist check passes, the tool fetches the URL and returns the full page content as markdown (fetch_apify_docs.ts:69-103):

typescript
const response = await fetch(url);
// ...
const html = await response.text();
markdown = htmlToMarkdown(html);
// ...
return buildMCPResponse({ texts: [`Fetched content from ${url}:\n\n${markdown}`], ... });

The HTML is converted to markdown and returned verbatim to the LLM. This creates a prompt injection vector - the attacker's page can contain instructions that the LLM may follow.

While tools like get-html-skeleton have no domain allowlist at all - it accepts any URL. The fetch-apify-docs tool was clearly intended to be more restricted (documentation-only), but the startsWith check defeats that intent.

PoC

json
{
  "method": "tools/call",
  "params": {
    "name": "fetch-apify-docs",
    "arguments": {
      "url": "https://docs.apify.com.evil.com/prompt-injection-payload"
    }
  }
}

The URL passes the startsWith('https://docs.apify.com') check, fetches the attacker's page, and returns its content to the LLM.

Impact

  • Prompt injection via fetched content: Attacker hosts a page at docs.apify.com.evil.com containing LLM instructions. When the tool fetches and returns this content, the LLM may follow the injected instructions.
  • Security boundary violation: The allowlist was explicitly designed to restrict fetching to trusted documentation domains. The bypass defeats this intent.
  • SSRF (limited): The tool can fetch from attacker-controlled servers, though the primary risk is the content returned to the LLM rather than network access.
  • Account compromise via _meta.apifyToken: Injected prompt instructions can direct the LLM to include a specific _meta.apifyToken (the server's per-request token feature) in subsequent call-actor invocations, redirecting billable operations to a victim's account or accessing their private Actors

AnalysisAI

Domain allowlist bypass in Apify MCP Server's fetch-apify-docs tool (npm/@apify/actors-mcp-server < 0.9.21) enables prompt injection against LLM agents by allowing attacker-controlled URLs to pass a flawed string prefix check. The tool validates requested URLs with String.startsWith() rather than parsing the URL hostname, so crafted URLs like https://docs.apify.com.evil.com/ satisfy the check while resolving to an attacker-controlled server. Publicly available exploit code (PoC) exists per the GitHub advisory GHSA-jwp7-wg77-3w9v; no CISA KEV listing at time of analysis, though the prompt injection vector can escalate to Apify account compromise via injected token redirection.

Technical ContextAI

The affected package is @apify/actors-mcp-server (npm), a Node.js-based Model Context Protocol server for the Apify automation platform. The flaw resides in src/tools/common/fetch_apify_docs.ts at line 51, where the allowlist check reads: ALLOWED_DOC_DOMAINS.some((domain) => url.startsWith(domain)), validating against the string literals 'https://docs.apify.com' and 'https://crawlee.dev' defined in src/const.ts. CWE-20 (Improper Input Validation) is the root cause: string prefix matching against raw URL strings does not account for DNS-level disambiguation between hostnames. A URL like https://docs.apify.com.evil.com starts with the required prefix lexically but resolves to a completely different host. Node.js's fetch() will follow the actual DNS resolution, fetching from the attacker's server, while the guard treats the URL as trusted. The fetched HTML is converted to markdown and returned verbatim to the LLM (fetch_apify_docs.ts:69-103), making this a direct prompt injection channel. Proper mitigation requires parsing the URL hostname component via the URL constructor and comparing it against the allowed set.

RemediationAI

Upgrade @apify/actors-mcp-server to version 0.9.21 or later, which is the vendor-released patch confirmed in the npm advisory. The fix replaces the String.startsWith() check with proper URL hostname parsing using the URL constructor, ensuring that only requests to the exact allowed hostnames (docs.apify.com, crawlee.dev) are permitted. Prior to patching, a specific compensating control is to configure network egress rules on the host running the MCP server to block outbound HTTP/HTTPS requests to any domain other than docs.apify.com and crawlee.dev - this prevents the server from actually reaching attacker infrastructure even if the bypass occurs, though it does not protect against cached or pre-fetched malicious content already in the pipeline. A second compensating control is to disable the fetch-apify-docs tool entirely in MCP server configuration if documentation fetching is not required for your use case; this eliminates the attack surface with no functional trade-off for deployments that do not use that tool. Full advisory: https://github.com/apify/apify-mcp-server/security/advisories/GHSA-jwp7-wg77-3w9v

CVE-2024-55591 CRITICAL POC
9.8 Jan 14

FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote

CVE-2014-7205 CRITICAL POC
10.0 Oct 08

Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t

CVE-2025-59528 CRITICAL POC
10.0 Sep 22

Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete

CVE-2017-14849 HIGH POC
7.5 Sep 28

Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc

CVE-2017-5941 CRITICAL POC
9.8 Feb 09

An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner

CVE-2014-3744 HIGH POC
7.5 Oct 23

Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi

CVE-2014-9566 HIGH POC
7.5 Mar 10

Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin

CVE-2013-4660 MEDIUM POC
6.8 Jun 28

The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic

CVE-2015-5688 MEDIUM POC
5.0 Sep 04

Directory traversal vulnerability in lib/app/index.js in Geddy before 13.0.8 for Node.js allows remote attackers to read

CVE-2026-45321 CRITICAL POC
9.6 May 12

Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio

CVE-2014-7192 CRITICAL POC
10.0 Dec 11

Eval injection vulnerability in index.js in the syntax-error package before 1.1.1 for Node.js 0.10.x, as used in IBM Rat

CVE-2013-4450 MEDIUM POC
5.0 Oct 21

The HTTP server in Node.js 0.10.x before 0.10.21 and 0.8.x before 0.8.26 allows remote attackers to cause a denial of se

Share

CVE-2026-46341 vulnerability details – vuln.today

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