GHSA-489g-7rxv-6c8qMedium· 6.5▾ SunlitMCP Atlassian: DNS-rebinding TOCTOU bypass of the SSRF fix (CVE-2026-27826)
▾ Sunlit zone — Low / medium · no exploitation signal
impact 35.8 · likelihood 0 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
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.
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).
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).
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.
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.
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.
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.
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.
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.
mcp-atlassian < 0.22.0Upgrade to a patched release:
mcp-atlassian 0.22.0Connected by shared product, vendor, weakness, or advisory.
GHSA-wm45-qh3g-v83fHigh· 7.7mcp-atlassian: Arbitrary server-side file read via attachment upload
GHSA-g5r6-gv6m-f5jvHigh· 7.7mcp-atlassian: Arbitrary file read via missing path validation in confluence_upload_attachment
CVE-2025-68616High· 7.5WeasyPrint helps web developers to create PDF documents
CVE-2026-6587Medium· 6.3A security flaw has been discovered in vibrantlabsai RAGAS up to 0.4.3
CVE-2026-32871Critical· 10.0FastMCP is a Pythonic way to build MCP servers and clients
CVE-2023-26735High· 7.5blackbox_exporter v0.23.0 was discovered to contain an access control issue in its probe interface