{"id":"GHSA-f9hh-cmx9-2f23","kind":"vulnerability","aliases":["GHSA-f9hh-cmx9-2f23"],"related":[],"title":"mcp-server-fetch: robots.txt path-canonicalization bypass (e.g. //private fetched while Disallow: /private)","description":"## Summary\n\n`mcp-server-fetch` matches `robots.txt` rules against the request path exactly as the client spelled it, while a typical origin resolves the path (collapse duplicate slashes, decode separator/dot escapes, remove `.`/`..` segments) before serving. With `Disallow: /private`, an autonomous `fetch` of `https://example.com//private` (and similar alternate spellings) therefore passes the robots check and returns the body of the page the site asked not to be crawled.\n\nThis is a policy-enforcement bypass of the control the server documents for model-initiated fetches (`src/fetch/README.md`, \"Customization - robots.txt\"). It is not an authentication bypass: the origin was already serving the content over plain HTTP.\n\n**Severity: Low.** No auth bypass, no SSRF / private-address bypass, no RCE, no crash. `robots.txt` is advisory crawler policy; the impact is defeating the advertised autonomous-fetch guarantee.\n\n## Distinct from GHSA-3jqg-r5pp-rmp2\n\n[GHSA-3jqg-r5pp-rmp2](https://github.com/modelcontextprotocol/servers/security/advisories/GHSA-3jqg-r5pp-rmp2) was a redirect-hop robots re-check gap (fixed so each hop is checked). This report is a different root cause: even with per-hop checks present, the path comparison itself does not canonicalize. Tested on commit `36380287ed3b15d115b55f546617d723072b1296` (`mcp-server-fetch` 2026.11.4), which already includes the hop fix.\n\n## Affected\n\n- Package: `mcp-server-fetch` (PyPI), under `src/fetch`\n- Tested: 2026.11.4, commit `36380287ed3b15d115b55f546617d723072b1296`\n- Comparison site: `src/fetch/src/mcp_server_fetch/server.py` around the `Protego` `can_fetch()` call in `check_may_autonomously_fetch_url()` (about line 532 at that commit). Spot-checks of older revisions since robots support was added show the same non-canonical comparison; we are not claiming every intermediate release.\n\n## Reproduction (localhost only)\n\nUses the project's own `FakeWeb` harness — no network and no live site. Save as `src/fetch/tests/test_repro_robots_bypass.py` and run:\n\n```\ncd src/fetch && uv run --frozen pytest tests/test_repro_robots_bypass.py -v\n```\n\n```python\nimport httpx\nimport pytest\nfrom mcp.types import CallToolResult\nfrom .harness import FakeWeb, connect\n\nROBOTS = \"https://example.com/robots.txt\"\nPRIVATE = \"the private page\"\n\ndef page(body):\n    return httpx.Response(\n        200, content=body.encode(), headers={\"content-type\": \"text/plain\"}\n    )\n\ndef robots():\n    return page(\"User-agent: *\\nDisallow: /private\")\n\ndef text_of(result: CallToolResult) -> str:\n    return result.model_dump(by_alias=True, mode=\"json\", exclude_none=True)[\n        \"content\"\n    ][0][\"text\"]\n\nasync def test_control_is_refused(web: FakeWeb) -> None:\n    \"\"\"Control: the plain path is refused today, so the rule is enforced.\"\"\"\n    web.add(ROBOTS, robots())\n    web.add(\"https://example.com/private\", page(PRIVATE))\n    async with connect() as (session, _):\n        result = await session.call_tool(\"fetch\", {\"url\": \"https://example.com/private\"})\n    assert result.is_error is True\n    assert PRIVATE not in text_of(result)\n\n@pytest.mark.parametrize(\n    \"url\",\n    [\"https://example.com//private\", \"https://example.com/a%2f..%2fprivate\"],\n)\nasync def test_alternate_spelling_leaks(web: FakeWeb, url) -> None:\n    \"\"\"These spell the disallowed page differently; the origin still serves it.\"\"\"\n    web.add(ROBOTS, robots())\n    web.add(url, page(PRIVATE))\n    async with connect() as (session, _):\n        result = await session.call_tool(\"fetch\", {\"url\": url})\n    assert result.is_error is True, \"the disallowed page was fetched\"\n    assert PRIVATE not in text_of(result)\n\nasync def test_redirect_to_encoded_dots_leaks(web: FakeWeb) -> None:\n    \"\"\"A redirect target is not passed through Pydantic's AnyUrl.\"\"\"\n    web.add(ROBOTS, robots())\n    web.add(\n        \"https://example.com/go\",\n        httpx.Response(302, headers={\"location\": \"/%2e%2e/private\"}),\n    )\n    web.add(\"https://example.com/%2e%2e/private\", page(PRIVATE))\n    async with connect() as (session, _):\n        result = await session.call_tool(\"fetch\", {\"url\": \"https://example.com/go\"})\n    assert result.is_error is True, \"the disallowed page was fetched\"\n    assert PRIVATE not in text_of(result)\n```\n\nOn the tested revision the control passes and the three bypass tests fail (`AssertionError: the disallowed page was fetched`).\n\n| Request path | Path Protego compares | Path HTTPX sends | Path a normalizing origin serves |\n|---|---|---|---|\n| `/private` | `/private` | `/private` | `/private` (blocked) |\n| `//private` | `//private` | `//private` | `/private` (fetched) |\n| `/a%2f..%2fprivate` | `/a%2F..%2Fprivate` | `/a%2f..%2fprivate` | `/private` (fetched) |\n| `/%2e%2e/private` (via redirect `Location`) | `/../private` | `/%2e%2e/private` | `/private` (fetched) |\n\nWe also confirmed against a local Python `http.server` origin (path resolution comparable to nginx/Apache-style serving): `GET /private` refused by robots; `GET //private` and the encoded-dot redirect target returned the private file on the wire. An origin that does not normalize returns 404, so there is no bypass there.\n\nNotes on scope: `/%2e%2e/private` works through a redirect `Location` (Pydantic `AnyUrl` normalizes that form on a direct argument and correctly blocks it). `//private` works as a direct argument; as a redirect target HTTPX treats scheme-relative `//private` as host `private`. Cross-host redirects still re-check the target host's robots.txt, so an attacker-controlled site that 302s to `https://victim.example/%2e%2e/private` can miss the victim's rule the same way.\n\n## Impact assumptions\n\n- Autonomous (model-initiated) `fetch` with robots enforcement on (default); the intentional prompt-fetch robots exemption is out of scope.\n- Attacker influences a URL the agent fetches (directly or via redirect).\n- Target publishes a path-specific `Disallow`, and its origin resolves the alternate spelling to that resource.\n\n## Suggested fix\n\nResolve the request path the way an origin does before matching rules, and require **both** the literal spelling and the resolved path to be allowed (`and`). Decode only separator/dot escapes (`%2f`/`%2F`/`%2e`/`%2E`), collapse duplicate slashes, and remove `.`/`..` per RFC 3986 §5.2.4; leave ordinary escapes such as `%20` alone. Derive the wire path with `urlsplit`/`urlunsplit` rather than from a URL object that HTTPX/Pydantic may already have normalized. Keep the existing `can_fetch(str(url), …)` check and add the second check — the change only ever adds refusals.\n\nHappy to share a tested patch + regression file against the project's harness privately if useful.\n\n---\n\nThis issue was identified with AI-assisted static code review and checked against the source before reporting; happy to answer questions or help with a fix.","summary":"The mcp-server-fetch MCP server compares robots.txt rules against the request path as written, without normalizing it the way web origins do. An attacker who can steer a model-initiated fetch can therefore retrieve pages a site disallowed in robots.txt, such as //private when Disallow: /private is set.","severity":"low","cvss":3.1,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"mcp-server-fetch","fixed":["2026.11.11"],"affected":">= 0.6.1, < 2026.11.11","ecosystem":"pypi"}],"ecosystems":["pypi"],"tags":["ai-tooling","claude-code","cwe-41","cwe-706","mcp","python"],"not_affected_if":["auth-required","default-config"],"how_to_check":"- Check the installed `mcp-server-fetch` version with `pip show mcp-server-fetch` or `uv pip show mcp-server-fetch`; versions from `>= 0.6.1` and `< 2026.11.11` are affected.\n- Confirm whether the server runs with robots.txt enforcement on, which is the default.\n- Check whether agents using the server can be given URLs from untrusted input or redirects.","fix":"- `mcp-server-fetch`: `2026.11.11`","status":"open","published_at":"2026-11-11T07:27:04+00:00","first_seen_at":"2026-11-11T07:28:35+00:00","triaged_at":"2026-11-11T07:30:02+00:00","updated_at":"2026-11-11T07:30:02+00:00","category":"ai-tooling","confidence":0.8,"triage":{"at":"2026-11-11T07:30:02Z","model":"claude-haiku-5-5","output":{"fix":"- `mcp-server-fetch`: `2026.11.11`","reach":"internet","title":"mcp-server-fetch: robots.txt check misses alternate path spellings like //private","impact":"low","summary":"The mcp-server-fetch MCP server compares robots.txt rules against the request path as written, without normalizing it the way web origins do. An attacker who can steer a model-initiated fetch can therefore retrieve pages a site disallowed in robots.txt, such as //private when Disallow: /private is set.","audience":"developers","category":"ai-tooling","nicknames":[],"who_cares":["mcp","python","claude-code"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"Pages a site disallowed for crawlers are returned to the agent","analyst_note":"","how_to_check":"- Check the installed `mcp-server-fetch` version with `pip show mcp-server-fetch` or `uv pip show mcp-server-fetch`; versions from `>= 0.6.1` and `< 2026.11.11` are affected.\n- Confirm whether the server runs with robots.txt enforcement on, which is the default.\n- Check whether agents using the server can be given URLs from untrusted input or redirects.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["default-config","auth-required"],"who_is_affected":"Teams running the mcp-server-fetch MCP server so an AI agent can fetch web pages, with robots.txt enforcement on by default. Exposure needs an attacker to influence a URL the agent fetches, directly or through a redirect, and a target site that uses path-specific Disallow rules and serves alternate spellings of those paths. Teams that do not run this server, or that only fetch fixed trusted URLs, can skip it.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"no","severity_if_unknown":"low"},"cost_usd":0.001044,"input_tokens":7200,"output_tokens":647,"severity_before":"low"},"analyst_status":null,"analyst_note":null,"search":"'-41':37B '-706':39B '/%2e%2e/private':605C '//private':137C,507C '/a%2f..%2fprivate':510C '/go':595C '/modelcontextprotocol/servers/security/advisories/ghsa-3jqg-r5pp-rmp2)':242C '/private':11A,15A,87B,90B,130C,426C,474C,490C '/robots.txt':400C '0':445C '200':410C '2026.11.4':288C,305C '2e':600C '2e/private':601C '2f23':20A,25A '302':597C '36380287ed3b15d115b55f546617d723072b1296':283C,307C '3jqg':232C,237C '532':325C 'add':339C 'address':207C 'advertis':223C 'advisori':215C 'affect':295C 'agent':424C 'ai':31B 'ai-tool':30B 'alia':437C 'alreadi':191C,290C 'altern':140C,514C 'anyurl':588C 'around':311C 'ask':156C 'assert':491C,496C,551C,561C 'async':447C,477C,511C,539C,568C,608C 'attack':67B 'auth':201C 'authent':186C 'autonom':132C,225C,320C 'autonomous-fetch':224C 'await':483C,545C 'bodi':150C,407C 'body.encode':412C 'bypass':9A,167C,187C,202C,208C 'call':316C 'calltoolresult':391C,431C 'canon':345C 'canonic':8A,279C 'caus':265C 'cd':375C 'check':146C,251C,258C,271C,318C,331C 'claim':350C 'claud':34B 'claude-cod':33B 'client':108C 'cmx9':19A,24A 'code':35B 'collaps':118C 'commit':282C,306C,328C 'compar':49B 'comparison':275C,308C,346C 'connect':396C,479C,541C 'content':194C,411C,415C,444C 'content-typ':414C 'control':170C,450C,456C 'crash':212C 'crawl':160C 'crawler':216C 'custom':180C 'cwe':36B,38B 'decod':121C 'def':405C,418C,427C,448C,512C,569C 'defeat':221C 'differ':263C,526C 'disallow':14A,82B,89B,129C,524C,557C 'distinct':228C 'document':173C 'dot':574C 'dump':435C 'duplic':119C 'e.g':10A 'encod':573C 'enforc':166C,467C 'error':493C,553C 'escap':123C 'even':266C 'everi':351C 'exact':105C 'example.com':136C,399C,473C,489C,506C,509C,594C,604C 'example.com/%2e%2e/private':603C 'example.com//private':135C,505C 'example.com/a%2f..%2fprivate':508C 'example.com/go':593C 'example.com/private':472C,488C 'example.com/robots.txt':398C 'exclud':441C 'f9hh':18A,23A 'fakeweb':362C,395C,454C,518C,577C 'fetch':4A,12A,29A,46B,75B,97C,133C,178C,226C,287C,300C,315C,321C,486C,548C,560C 'fix':253C,294C 'frozen':379C 'gap':252C 'ghsa':17A,22A,231C,236C 'ghsa-3jqg-r5pp-rmp2':230C,235C 'ghsa-f9hh-cmx9-2f23':16A,21A 'github.com':241C 'github.com/modelcontextprotocol/servers/security/advisories/ghsa-3jqg-r5pp-rmp2)':240C 'guarante':227C 'har':363C,393C 'header':413C,598C 'hop':247C,256C,270C,293C 'http':197C 'httpx':385C 'httpx.response':409C,596C 'impact':219C 'import':384C,386C,390C,394C 'includ':291C 'initi':74B,177C 'intermedi':352C 'json':440C 'leak':516C,575C 'line':324C 'live':368C 'localhost':355C 'locat':599C 'low':199C 'match':98C 'may':319C 'mcp':2A,27A,40B,44B,47B,95C,285C,298C 'mcp-server-fetch':1A,26A,43B,94C,284C,297C 'mcp.types':389C 'mode':439C 'model':73B,176C 'model-initi':72B,175C 'ndisallow':425C 'network':365C 'non':344C 'non-canon':343C 'none':442C,455C,520C,578C 'normal':59B 'older':333C 'origin':64B,114C,189C,528C 'packag':296C 'page':79B,153C,404C,406C,421C,475C,525C,537C,558C,606C 'pass':143C,584C 'path':7A,55B,104C,117C,274C,459C 'path-canonic':6A 'per':269C 'per-hop':268C 'plain':196C,458C 'polici':165C,217C 'policy-enforc':164C 'present':272C 'privat':206C,401C,403C,476C,497C,538C,562C,607C 'private-address':205C 'project':359C 'protego':313C 'pydant':586C 'pypi':301C 'pytest':380C,387C 'pytest.mark.parametrize':503C 'python':41B,383C 'r5pp':233C,238C 'rce':210C 're':250C 're-check':249C 'redirect':246C,571C,580C 'redirect-hop':245C 'refus':452C,461C 'releas':353C 'remov':124C 'report':260C 'reproduct':354C 'request':54B,103C 'resolv':115C 'result':430C,482C,502C,544C,567C 'result.is':492C,552C 'result.model':434C 'retriev':78B 'return':148C,408C,420C,433C 'revis':334C 'rmp2':234C,239C 'robot':145C,248C,336C,397C,419C,469C,470C,533C,534C,590C,591C 'robots.txt':5A,50B,84B,99C,181C,213C 'root':264C 'rule':51B,100C,465C 'run':374C,378C 'save':370C 'segment':125C 'separator/dot':122C 'serv':127C,192C,530C 'server':3A,28A,45B,48B,96C,172C,286C,299C 'session':481C,543C 'session.call':484C,546C 'set':92B 'sever':198C 'show':340C 'similar':139C 'sinc':335C 'site':81B,155C,309C,369C 'slash':120C 'spell':109C,141C,515C,522C 'spot':330C 'spot-check':329C 'src/fetch':303C,376C 'src/fetch/readme.md':179C 'src/fetch/src/mcp_server_fetch/server.py':310C 'src/fetch/tests/test_repro_robots_bypass.py':372C 'ssrf':204C 'steer':70B 'still':529C 'str':432C 'summari':93C 'support':337C 'target':581C 'test':280C,304C,449C,513C,570C 'tests/test_repro_robots_bypass.py':381C 'text':428C,446C,500C,565C 'text/plain':417C 'therefor':77B,142C 'today':462C 'tool':32B,485C,547C 'true':438C,443C,495C,555C 'type':416C 'typic':113C 'url':322C,487C,504C,519C,536C,549C,550C 'use':357C 'user':423C 'user-ag':422C 'uv':377C 'v':382C 'way':62B 'web':63B,453C,517C,576C 'web.add':468C,471C,532C,535C,589C,592C,602C 'without':58B 'written':57B","nicknames":[],"mitigations":[],"who_affected":"Teams running the mcp-server-fetch MCP server so an AI agent can fetch web pages, with robots.txt enforcement on by default. Exposure needs an attacker to influence a URL the agent fetches, directly or through a redirect, and a target site that uses path-specific Disallow rules and serves alternate spellings of those paths. Teams that do not run this server, or that only fetch fixed trusted URLs, can skip it.","tier":"B","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["mcpserverfetch"],"ptokens":["fetch","mcp","server"],"labels":["aitooling","claudecode","cwe41","cwe706","low","mcp","pypi","python"],"campaign_type":null,"search_a":"'/private':11A,15A '2f23':20A,25A 'bypass':9A 'canonic':8A 'cmx9':19A,24A 'disallow':14A 'e.g':10A 'f9hh':18A,23A 'fetch':4A,12A,29A 'ghsa':17A,22A 'ghsa-f9hh-cmx9-2f23':16A,21A 'mcp':2A,27A 'mcp-server-fetch':1A,26A 'path':7A 'path-canonic':6A 'robots.txt':5A 'server':3A,28A","search_b":"'-41':37B '-706':39B '/private':87B,90B 'ai':31B 'ai-tool':30B 'attack':67B 'claud':34B 'claude-cod':33B 'code':35B 'compar':49B 'cwe':36B,38B 'disallow':82B,89B 'fetch':46B,75B 'initi':74B 'mcp':40B,44B,47B 'mcp-server-fetch':43B 'model':73B 'model-initi':72B 'normal':59B 'origin':64B 'page':79B 'path':55B 'python':41B 'request':54B 'retriev':78B 'robots.txt':50B,84B 'rule':51B 'server':45B,48B 'set':92B 'site':81B 'steer':70B 'therefor':77B 'tool':32B 'way':62B 'web':63B 'without':58B 'written':57B","search_c":"'/%2e%2e/private':605C '//private':137C,507C '/a%2f..%2fprivate':510C '/go':595C '/modelcontextprotocol/servers/security/advisories/ghsa-3jqg-r5pp-rmp2)':242C '/private':130C,426C,474C,490C '/robots.txt':400C '0':445C '200':410C '2026.11.4':288C,305C '2e':600C '2e/private':601C '302':597C '36380287ed3b15d115b55f546617d723072b1296':283C,307C '3jqg':232C,237C '532':325C 'add':339C 'address':207C 'advertis':223C 'advisori':215C 'affect':295C 'agent':424C 'alia':437C 'alreadi':191C,290C 'altern':140C,514C 'anyurl':588C 'around':311C 'ask':156C 'assert':491C,496C,551C,561C 'async':447C,477C,511C,539C,568C,608C 'auth':201C 'authent':186C 'autonom':132C,225C,320C 'autonomous-fetch':224C 'await':483C,545C 'bodi':150C,407C 'body.encode':412C 'bypass':167C,187C,202C,208C 'call':316C 'calltoolresult':391C,431C 'canon':345C 'canonic':279C 'caus':265C 'cd':375C 'check':146C,251C,258C,271C,318C,331C 'claim':350C 'client':108C 'collaps':118C 'commit':282C,306C,328C 'comparison':275C,308C,346C 'connect':396C,479C,541C 'content':194C,411C,415C,444C 'content-typ':414C 'control':170C,450C,456C 'crash':212C 'crawl':160C 'crawler':216C 'custom':180C 'decod':121C 'def':405C,418C,427C,448C,512C,569C 'defeat':221C 'differ':263C,526C 'disallow':129C,524C,557C 'distinct':228C 'document':173C 'dot':574C 'dump':435C 'duplic':119C 'encod':573C 'enforc':166C,467C 'error':493C,553C 'escap':123C 'even':266C 'everi':351C 'exact':105C 'example.com':136C,399C,473C,489C,506C,509C,594C,604C 'example.com/%2e%2e/private':603C 'example.com//private':135C,505C 'example.com/a%2f..%2fprivate':508C 'example.com/go':593C 'example.com/private':472C,488C 'example.com/robots.txt':398C 'exclud':441C 'fakeweb':362C,395C,454C,518C,577C 'fetch':97C,133C,178C,226C,287C,300C,315C,321C,486C,548C,560C 'fix':253C,294C 'frozen':379C 'gap':252C 'ghsa':231C,236C 'ghsa-3jqg-r5pp-rmp2':230C,235C 'github.com':241C 'github.com/modelcontextprotocol/servers/security/advisories/ghsa-3jqg-r5pp-rmp2)':240C 'guarante':227C 'har':363C,393C 'header':413C,598C 'hop':247C,256C,270C,293C 'http':197C 'httpx':385C 'httpx.response':409C,596C 'impact':219C 'import':384C,386C,390C,394C 'includ':291C 'initi':177C 'intermedi':352C 'json':440C 'leak':516C,575C 'line':324C 'live':368C 'localhost':355C 'locat':599C 'low':199C 'match':98C 'may':319C 'mcp':95C,285C,298C 'mcp-server-fetch':94C,284C,297C 'mcp.types':389C 'mode':439C 'model':176C 'model-initi':175C 'ndisallow':425C 'network':365C 'non':344C 'non-canon':343C 'none':442C,455C,520C,578C 'older':333C 'origin':114C,189C,528C 'packag':296C 'page':153C,404C,406C,421C,475C,525C,537C,558C,606C 'pass':143C,584C 'path':104C,117C,274C,459C 'per':269C 'per-hop':268C 'plain':196C,458C 'polici':165C,217C 'policy-enforc':164C 'present':272C 'privat':206C,401C,403C,476C,497C,538C,562C,607C 'private-address':205C 'project':359C 'protego':313C 'pydant':586C 'pypi':301C 'pytest':380C,387C 'pytest.mark.parametrize':503C 'python':383C 'r5pp':233C,238C 'rce':210C 're':250C 're-check':249C 'redirect':246C,571C,580C 'redirect-hop':245C 'refus':452C,461C 'releas':353C 'remov':124C 'report':260C 'reproduct':354C 'request':103C 'resolv':115C 'result':430C,482C,502C,544C,567C 'result.is':492C,552C 'result.model':434C 'return':148C,408C,420C,433C 'revis':334C 'rmp2':234C,239C 'robot':145C,248C,336C,397C,419C,469C,470C,533C,534C,590C,591C 'robots.txt':99C,181C,213C 'root':264C 'rule':100C,465C 'run':374C,378C 'save':370C 'segment':125C 'separator/dot':122C 'serv':127C,192C,530C 'server':96C,172C,286C,299C 'session':481C,543C 'session.call':484C,546C 'sever':198C 'show':340C 'similar':139C 'sinc':335C 'site':155C,309C,369C 'slash':120C 'spell':109C,141C,515C,522C 'spot':330C 'spot-check':329C 'src/fetch':303C,376C 'src/fetch/readme.md':179C 'src/fetch/src/mcp_server_fetch/server.py':310C 'src/fetch/tests/test_repro_robots_bypass.py':372C 'ssrf':204C 'still':529C 'str':432C 'summari':93C 'support':337C 'target':581C 'test':280C,304C,449C,513C,570C 'tests/test_repro_robots_bypass.py':381C 'text':428C,446C,500C,565C 'text/plain':417C 'therefor':142C 'today':462C 'tool':485C,547C 'true':438C,443C,495C,555C 'type':416C 'typic':113C 'url':322C,487C,504C,519C,536C,549C,550C 'use':357C 'user':423C 'user-ag':422C 'uv':377C 'v':382C 'web':453C,517C,576C 'web.add':468C,471C,532C,535C,589C,592C,602C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-11T07:27:04+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-f9hh-cmx9-2f23","url":"https://github.com/modelcontextprotocol/servers/security/advisories/GHSA-f9hh-cmx9-2f23","severity":"low","published_at":"2026-11-11T07:27:04+00:00","modified_at":"2026-11-11T07:27:04+00:00","first_seen_at":"2026-11-11T07:28:35+00:00","fetched_at":"2026-11-11T07:28:35+00:00","note":null}],"documents":[{"id":123648,"url":"https://github.com/modelcontextprotocol/servers/security/advisories/GHSA-f9hh-cmx9-2f23","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}