[ ⌘K ]
← BACK TO SEARCH

elizabethsiegle/remote-mcp-server-authless-andor

critical

Remote MCP server to summarize/scrape Andor season 2 episodes using Browser Rendering and Workers AI

This MCP server scrapes plot summaries for Andor Season 2 episodes from the Star Wars Fandom wiki using Cloudflare's Browser Rendering, then generates...

purpose: This MCP server scrapes plot summaries for Andor Sthreat: network exposed
TypeScript1May 20, 2026May 20, 2026GITHUB
browser-renderingclaudeclaude-mcpcloudflarecloudflare-browser-renderingcloudflare-mcpcloudflare-workersmcpmodelcontextprotocol
5/20/2026
high1 finding
src/index.ts
362const messages = [
363	{ 
364		role: "system", 
365		content: "You are a Star Wars expert..." 
366	},
367	{
368		role: "user",
369		content: `Episode: ${episode}\nPlot Summary:\n${episodeContent}`
370	}
371];
372
373const analysis = await (env as any).AI.run("@cf/meta/llama-4-scout-17b-16e-instruct", { messages });
src/index.ts:1-5

// Exploitable if the MCP is exposed to untrusted prompts (e.g., via public SSE endpoint).

The 'episode' parameter from the user is directly interpolated into the AI prompt without sanitization. An attacker could inject malicious instructions into the episode string, causing the AI to ignore its system prompt and perform unintended actions, such as generating harmful content or leaking information.

ImpactAn attacker could manipulate the AI's output, potentially causing it to produce misleading or dangerous summaries, or to reveal sensitive information if the AI has access to such data.

FixSanitize or escape the episode parameter before including it in the prompt. Consider using a separate input validation step or treating the episode as a label rather than free text.

high1 finding
src/index.ts
238const episodeUrl = new URL(episodeLink, baseUrl).toString();
src/index.ts:1-5

// Exploitable if an attacker can influence the scraped wiki page content (e.g., via prompt injection or compromised wiki).

The episode link is extracted from the scraped page and used to construct a URL for navigation. While the link comes from the same origin (starwars.fandom.com), an attacker could potentially manipulate the scraped content (e.g., via a compromised wiki page or a prompt injection that alters the page content) to inject a malicious href attribute, leading to an SSRF attack where the headless browser navigates to an attacker-controlled URL.

ImpactAn attacker could cause the server to make requests to arbitrary internal or external URLs, potentially accessing internal services, exfiltrating data, or performing further attacks.

FixValidate that the episodeLink is a relative path or belongs to the expected domain (starwars.fandom.com) before constructing the URL. Use a URL parser to check the hostname.

high1 finding
src/index.ts
238const episodeUrl = new URL(episodeLink, baseUrl).toString();
239console.log('Navigating to episode page:', episodeUrl);
240
241// Add retry logic for page loading
242let episodeResponse = null;
243let retryCount = 0;
244const maxRetries = 3;
245
246while (retryCount < maxRetries) {
247  try {
248    episodeResponse = await page.goto(episodeUrl, {
249      waitUntil: 'networkidle0',
250      timeout: 30000
251    });
src/index.ts:1-5

// Exploitable if the wiki page content is manipulated or if the MCP server is exposed to untrusted prompts that can influence the episode parameter.

The tool navigates to a URL constructed from the episode link extracted from the wiki page. However, the episode parameter is used to find the link, and if an attacker can control the wiki content or inject a malicious link, the browser could be directed to an arbitrary URL. Additionally, the base URL is hardcoded, but the episode link is derived from the page content, which could be manipulated if the wiki is compromised or if the tool is used against a different base URL. The primary risk is that the episode parameter is not validated and could lead to navigation to unintended sites if the wiki page structure is altered.

ImpactAn attacker could potentially redirect the browser to an arbitrary URL, leading to SSRF attacks, data exfiltration, or interaction with internal services if the MCP server is deployed in a network that allows such access.

FixValidate that the episode link is a relative path or belongs to the expected domain (starwars.fandom.com). Use a URL parser to ensure the final URL is within the allowed scope.

medium1 finding
src/index.ts
110episode: z.string().describe("The episode number or title to get a summary for"),
111		},
112		async ({ episode }: { episode: string }) => {
src/index.ts:1-5

// Exploitable if the MCP is exposed to untrusted prompts.

The episode parameter is only validated as a string via Zod, but no further validation is performed to ensure it matches expected episode numbers or titles. This allows arbitrary strings to be passed, which could lead to unexpected behavior in the scraping logic (e.g., matching unintended rows) or prompt injection.

ImpactAn attacker could provide unexpected input that causes the scraper to fail, return incorrect data, or trigger errors that leak information. Combined with prompt injection, this increases the attack surface.

FixAdd validation to restrict the episode parameter to a known set of values (e.g., '1', '2', '3', ... or specific titles) using Zod enums or regex.

medium1 finding
src/index.ts
367const messages = [
368  { 
369    role: "system", 
370    content: "You are a Star Wars expert..." 
371  },
372  {
373    role: "user",
374    content: `Episode: ${episode}\nPlot Summary:\n${episodeContent}`
375  }
376];
src/index.ts:1-5

// Exploitable if the MCP server is exposed to untrusted prompts, allowing an attacker to control the episode parameter.

The episode parameter is directly interpolated into the AI prompt without sanitization. While the AI model is not executing commands, this could allow prompt injection attacks where an attacker crafts an episode string that manipulates the AI's behavior or leaks information.

ImpactAn attacker could inject instructions into the AI prompt, potentially causing the AI to ignore its system prompt, generate misleading summaries, or reveal sensitive information if the AI has access to such data.

FixSanitize the episode parameter to remove any special characters or control sequences. Consider using a whitelist of allowed episode names or numbers.

medium1 finding
src/index.ts
157await page.setJavaScriptEnabled(true);
158await page.setBypassCSP(true);
src/index.ts:1-5

// Exploitable only if combined with SSRF or if the wiki page is compromised.

The browser is configured with JavaScript enabled and Content Security Policy (CSP) bypassed. While this is necessary for scraping the wiki, it also means that if the browser is directed to a malicious page (e.g., via SSRF), JavaScript could execute without restrictions, potentially leading to data exfiltration or further attacks.

ImpactIf an attacker can control the URL the browser navigates to, they could execute arbitrary JavaScript in the context of the browser, potentially stealing cookies, accessing internal resources, or performing actions on behalf of the MCP server.

FixDisable JavaScript if not strictly necessary, or restrict navigation to trusted domains. Consider using a more restrictive CSP or validating the final URL before navigation.

low1 finding
src/index.ts
158await page.setBypassCSP(true);
src/index.ts:1-5

// Exploitable only if the scraped wiki page is compromised, which is unlikely but possible.

The tool bypasses Content Security Policy (CSP) on the scraped pages. While this is common for scraping, it could allow the browser to load resources that would otherwise be blocked, potentially increasing the risk of XSS or data exfiltration if the scraped page is compromised.

ImpactIf the scraped wiki page is compromised with malicious scripts, bypassing CSP could allow those scripts to execute and exfiltrate data or perform actions within the browser context.

FixConsider not bypassing CSP unless necessary, or restrict the browser's capabilities further.

browser.automationshell.execauth.nonenetwork.httpenv.exposure
100
LLM-based
low findings+5
high findings+75
medium findings+45