GHSA-489g-7rxv-6c8q CVE-2026-73497
MCP Atlassian: DNS-rebinding TOCTOU bypass of the SSRF fix (CVE-2026-27826)
- Severity
- 6.5 / 10
- Medium · CVSS 3.1
- Exploit chance (EPSS)
- 0.38%
- Chance of exploitation in the next 30 days. Higher than 31.44% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-918 Server-Side Request Forgery (SSRF)
- Fix
0.22.0- Upgrade mcp-atlassian to this version or later
Description
Summary
GHSA-7r34-79r5-rcc9's fix added validate_url_for_ssrf, which resolves the attacker-controlled X-Atlassian-{Jira,Confluence}-Url header host once at middleware time and trusts the result. But the outbound request is later built with the raw hostname and re-resolves at connect time with no IP pinning. An attacker-controlled rebinding DNS name returns a public IP on the guard's lookup (validation passes) and 169.254.169.254 / an internal IP on the request's lookup (the socket connects there) → unauthenticated SSRF to cloud metadata / internal services on the patched build.
Relationship to CVE-2026-27826 / GHSA-7r34-79r5-rcc9 (incomplete fix — please read first)
This is an incomplete-fix sibling of the published GHSA-7r34-79r5-rcc9 (the X-Atlassian-*-Url header SSRF). That fix (PR #986/#1005) added a single middleware-time resolve + allowlist DNS-skip, but does not pin the validated IP to the connection — the fetcher re-resolves the raw hostname at connect time, so the documented SSRF mitigation is incomplete against DNS-rebinding. The other advisory GHSA-xjgw-4wvw-rgm4 (file-write) is unrelated. Verified live (2026-06-27): neither advisory, nor any open PR/issue (rebind/TOCTOU/getaddrinfo/pin → 0), covers connect-time re-resolution. Filing as an incomplete-fix of GHSA-7r34 (not a standalone fresh SSRF).
Affected
src/mcp_atlassian/utils/urls.py + servers/main.py + servers/dependencies.py, HEAD ba72540 (PyPI mcp-atlassian, patched ≥0.17.0). CWE-918 (SSRF) via CWE-367 (TOCTOU).
Vulnerable code
utils/urls.py validate_url_for_ssrf (≈184-205) resolves + validates, then returns a string verdict, not a pinned IP:
def validate_url_for_ssrf(url: str) -> str | None: # returns an error string or None — NO IP is pinned
...
# resolves the host, checks each resolved IP is global, then DISCARDS the IP
servers/main.py:526,534 calls it once in middleware. servers/dependencies.py:544-561 then builds the fetcher with url = <raw header hostname> (no pinned IP, no custom resolver / cached-getaddrinfo adapter), so the actual request re-resolves the name.
PoC (executed — boundary demonstration)
The PoC loads the real urls.py by path (importlib, sha256 printed) and drives the genuine validate_url_for_ssrf, simulating the two resolutions via getaddrinfo:
[CHECK ] validate_url_for_ssrf('http://rebind.attacker.example') -> None (getaddrinfo#1 = 93.184.216.34 global -> guard PASSED)
[CONNECT] getaddrinfo call #2 returned 169.254.169.254 -> the socket connects HERE
[PROOF ] guard validated IP 93.184.216.34 but connection targets 169.254.169.254 => SSRF on the PATCHED build
[CONTROL] if guard SAW 169.254.169.254 at check time -> blocks it correctly
[PIN ] validate_url_for_ssrf returns a verdict (None), NOT an IP; dependencies.py builds url=raw hostname -> NO pin
ALL PoC ASSERTIONS PASSED — DNS-rebind TOCTOU bypass demonstrated.
Honest scope of the PoC: this is a boundary demonstration — it proves the structural TOCTOU (the guard validates an IP it then discards; the connection re-resolves an unpinned hostname). It does not demonstrate a live end-to-end SSRF on a running server; that additionally requires an attacker-controlled fast-rebinding authoritative DNS responder winning the resolve→connect window. Flagging this explicitly rather than overclaiming.
Impact
Same as parent GHSA-7r34 (unauth read of cloud-metadata IAM creds / internal-service reach), reachable again on the patched version. The X-Atlassian-*-Url headers are processed in UserTokenMiddleware before fetcher creation, so an unauthenticated/low-priv caller controls the host.
Severity
High — CVSS v3.1 AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N ≈ 7.x, aligned to the parent (8.2) with AC:H for the rebinding-race precondition. Honest caveat (above): the executed PoC proves the missing IP-pin structurally; a live exploit additionally needs an attacker rebinding-DNS. Not Critical.
Remediation
Pin the connection to the IP that validate_url_for_ssrf validated: use a custom resolver / cached-getaddrinfo requests-adapter (or pass the validated IP with a Host header), so the connect cannot re-resolve to a different address.
Dedup / freshness (re-verified live 2026-06-27)
Advisories GHSA-7r34-79r5-rcc9 (original header SSRF this bypasses) + GHSA-xjgw-4wvw-rgm4 (file-write, unrelated). Neither covers connect-time re-resolution / rebinding. PR #986/#1005 (the fix) add a single middleware-time resolve + allowlist DNS-skip, no pinning. gh search prs/issues for rebind/TOCTOU/getaddrinfo/pin → 0. First-party code. Fresh at HEAD ba72540.
Affected versions
PyPI
| Package | Vulnerable | Fixed in |
|---|---|---|
| mcp-atlassian | < 0.22.0 |
0.22.0 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
mcp-atlassian PyPI → 0.22.0
- pip
pip install --upgrade "mcp-atlassian>=0.22.0"- poetry
poetry add "mcp-atlassian>=0.22.0"- uv
uv add "mcp-atlassian>=0.22.0"
Severity breakdown
CVSS 3.1 6.5
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N
- Attack vector
- Network
- Attack complexity
- High
- Privileges required
- None
- User interaction
- None
- Scope
- Unchanged
- Confidentiality
- High
- Integrity
- Low
- Availability
- None
Weakness
CWE-918: Server-Side Request Forgery (SSRF)
The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.
References
Packages
Other links
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-g2r2-3j32-j27x MCP Atlassian: Reflected XSS in OAuth Setup Callback Handler | Medium | Also affects mcp-atlassian |
| GHSA-h7wj-5v37-59r2 MCP Atlassian: Path traversal in upload_attachment allows arbitrary file read (incomplete fix for CVE-2026-27825) | Medium | Also affects mcp-atlassian |
| GHSA-4596-2p6p-28cv MCP Atlassian: Insecure File Permissions on OAuth Token Storage | Medium | Also affects mcp-atlassian |
| GHSA-mfv2-4wvm-9pgp MCP Atlassian: Path traversal in upload_attachment allows arbitrary file read and exfiltration via MCP tool call | Medium | Also affects mcp-atlassian |
| GHSA-p6hp-93wp-fh6p MCP Atlassian: Path Traversal / Arbitrary File Read in confluence_upload_attachment MCP tool (incomplete fix of GHSA-xjgw-4wvw-rgm4) | High | Also affects mcp-atlassian |
| GHSA-6cr4-ccf3-x7h4 MCP Atlassian: Arbitrary file read via confluence_upload_attachment allows exfiltration of server credentials | High | Also affects mcp-atlassian |
| GHSA-mrq8-fv7v-hhjg MCP Atlassian: HTTP upload tools accept arbitrary server-local file paths | Medium | Also affects mcp-atlassian |
| GHSA-2xj6-xx86-cwwc MCP Atlassian: Arbitrary File Read & Exfiltration (Confused Deputy) in JIRA update_issue | High | Also affects mcp-atlassian |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor