# MCP Atlassian: SSRF Protection Bypass

Backslash-before-userinfo URL bypasses mcp-atlassian's urlparse-based SSRF check, letting attacker-supplied Jira URL reach loopback/internal services via requests.

- Payout: Research
- Severity: high
- Program: mcp-atlassian
- Found by: RacerZ-fighting
- Disclosed: 2026-09-22
- CVE: CVE-2026-77274
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-hgcf-4mq8-5266
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-hgcf-4mq8-5266
- Tags: area:ai domain:ai domain:web impact:internal-access kind:research platform:ghsa sev:high tech:python technique:parser-differential vuln:ssrf

**Target:** MCP server HTTP transport (POST /mcp) with X-Atlassian-Jira-Url header
**Root cause:** validate_url_for_ssrf() validates parsed.hostname from urllib.parse.urlparse(), which resolves the payload host to www.baidu.com, while requests.Session interprets the same URL as 127.0.0.1:6666 and percent-encodes the backslash into the path.
**Steps:**
1. Start local server: `python3 -m http.server 6666 --bind 127.0.0.1`
2. Run mcp-atlassian with streamable HTTP transport on port 9000
3. Send initialize to `POST /mcp` with header `X-Atlassian-Jira-Url: http://127.0.0.1:6666\@www.baidu.com` and `X-Atlassian-Jira-Personal-Token: dummy-token`
4. Send `notifications/initialized` with returned `mcp-session-id` and same malicious URL header
5. Call `tools/call` `jira_get_issue` with `issue_key: TEST-1`; server requests `http://127.0.0.1:6666/%5C@www.baidu.com/rest/api/2/myself`
6. Observe local HTTP server receiving the request, confirming SSRF
**How found:** Noticed that the SSRF validator and the actual HTTP client parse URLs differently; crafted a URL with a backslash before @-userinfo so urlparse sees the benign host while requests routes to the loopback address.
**Exploitation:** Attacker controls the X-Atlassian-Jira-Url (or X-Atlassian-Confluence-Url) header on an MCP session; the SSRF validator approves the hostname www.baidu.com while the Atlassian client's requests.Session connects to 127.0.0.1:6666, forcing the server to issue requests to loopback/internal services.
**Insight:** When an SSRF filter uses urlparse().hostname but the sink uses requests/urllib3, test backslash-before-@ and similar userinfo tricks: the two parsers disagree on where the authority ends, so the validated host differs from the connected host.

