CVE-2026-77248: MCP Atlassian: Unauthenticated arbitrary local file read via upload_attachment file_path, chained with missing auth on streamable-http transport
On a default `--transport streamable-http` mcp-atlassian server, unauthenticated clients can call every tool, and `upload_attachment` reads any `file_path` on the server host. An attacker can upload `/proc/self/environ` to a page or issue and read it back, which exposes the operator's Atlassian API token and `.env` secrets. Versions up to 0.21.1 are affected; upgrade to 0.22.0.
Published Sep 22, 2026 · Analysis Oct 22, 2026
What an attacker can do
Two gaps combine. The streamable-http transport binds 0.0.0.0 by default (__init__.py). The OAuth-proxy provider is opt-in (ATLASSIAN_OAUTH_PROXY_ENABLE, off by default), so the server is built with auth=None. UserTokenMiddleware._parse_auth_header flags only a malformed Authorization header, and a request with none passes through. _get_fetcher in dependencies.py then falls back to the operator's global credentials from .env. check_write_access checks only read-only mode, so read and write tools are reachable.
The sink is upload_attachment: its file_path flows into open(file_path, 'rb') in confluence/attachments.py and jira/attachments.py with no validate_safe_path or allowlist, unlike the download flow. The proof of concept calls upload_attachment with /proc/self/environ and a page ID the attacker chooses, then reads the bytes back with download_attachment.
The result is unauthenticated arbitrary file read on the MCP server host, including ~/.ssh/id_rsa and /etc/passwd, plus unauthenticated use of every Atlassian tool as the operator, often an admin. The CVSS vector reflects network access with no privileges, a changed scope and high confidentiality impact.
Who is affected
mcp-atlassian up to and including 0.21.1 (the package data lists everything before 0.22.0) when run with --transport streamable-http and global operator Atlassian credentials, with the OAuth proxy not enabled. Anyone who can reach the port is a potential attacker.
pip show mcp-atlassianCheck whether the container publishes the port and whether ATLASSIAN_OAUTH_PROXY_ENABLE is set.
mcp-atlassian
- Ecosystem
- PyPI
- Affected
- < 0.22.0
- Fixed in
- 0.22.0
- Check
pip show mcp-atlassian
How to fix it
Upgrade to mcp-atlassian 0.22.0:
pip install -U mcp-atlassian==0.22.0The fix is PR #1448. The report's suggested fix is to require authentication on the streamable-http transport by default, never fall back to the operator's global credentials for unauthenticated requests, and apply validate_safe_path or an allowlist to the upload file_path. The sources give no workaround. As stopgaps, enable the OAuth proxy, put authentication in front of the port, bind to 127.0.0.1, and set READ_ONLY_MODE=true. Rotate the Atlassian token and any .env secrets if the server was exposed.
How to tell if you were hit
Look in the MCP server logs for tools/call of upload_attachment with file_path values such as /proc/self/environ, /etc/passwd or key paths, followed by download_attachment calls, from clients that sent no Authorization header. In Jira and Confluence, review recent attachments added by the operator account for files that contain environment variables or keys, and delete them. Check Atlassian audit logs for activity by the operator that was not theirs.
Original advisory
From the GitHub Advisory Database (CC BY 4.0).
Summary
In the documented multi-user HTTP deployment (--transport streamable-http with global operator Atlassian credentials), sooperset/mcp-atlassian exposes all tools to unauthenticated network clients, and the upload_attachment tool reads an attacker-supplied file_path with no path validation. Chained, an unauthenticated network attacker reads arbitrary files on the MCP server host (e.g. /proc/self/environ → the operator's Atlassian API token + .env secrets, ~/.ssh/id_rsa, /etc/passwd) by uploading them to an attacker-chosen page/issue and reading them back.
Details
Missing authentication (transport):
- streamable-http binds
0.0.0.0by default (src/mcp_atlassian/__init__.py:151). - The OAuth-proxy auth provider is opt-in (
ATLASSIAN_OAUTH_PROXY_ENABLE, default false), somain_mcpis built withauth=None(src/mcp_atlassian/servers/main.py:724-731, 813-817). UserTokenMiddleware._parse_auth_headersetsauth_validation_erroronly for a *malformed* Authorization header; a request with no Authorization header passes through (main.py:416-446, 582-595)._get_fetcherthen falls through to the global credential fallback using the operator's.envAtlassian token (src/mcp_atlassian/servers/dependencies.py:644-676).check_write_accessgates only on read-only mode, not auth → read and write tools reachable.
Arbitrary file read (sink):
upload_attachment'sfile_pathflows unsanitized intoopen(file_path, 'rb')— Confluencesrc/mcp_atlassian/confluence/attachments.py:477(fromservers/confluence.py:1294-1369); Jirasrc/mcp_atlassian/jira/attachments.py:386(fromservers/jira.py:1609-1673). Novalidate_safe_path/ allowlist (contrast the download flow, hardened after CVE-2026-27825).
Proof of Concept
# unauthenticated (no Authorization header) against a default streamable-http deployment:
tools/call upload_attachment { "file_path": "/proc/self/environ", "page_id": "<attacker-chosen>" }
# then read it back:
tools/call download_attachment { ... } # returns the bytes (base64) -> operator's ATLASSIAN token + .env secretsImpact
Unauthenticated arbitrary local file read on the MCP server host — including the operator's Atlassian API token and .env secrets — a boundary the Atlassian-scoped tool must not cross, plus unauthenticated use of every read/write Atlassian tool as the operator's (often admin) principal. Distinct from GHSA-xjgw-4wvw-rgm4 (file *write* via download_path) and GHSA-7r34-79r5-rcc9 (URL-header SSRF).
Suggested fix
Require authentication on the streamable-http transport by default (do not fall back to operator global credentials for unauthenticated requests); apply validate_safe_path/allowlist to file_path in upload_attachment as the download flow already does.
Affected
mcp-atlassian <= 0.21.1.
Credited to koonnamchok.
Questions
- Is a login needed to read files with this flaw?
No. A request with no
Authorizationheader passes the middleware on a default streamable-http deployment and runs with the operator's global credentials.- Which secrets are at risk?
Anything the server process can read: the operator's Atlassian API token and
.envvalues via/proc/self/environ, SSH private keys, and system files such as/etc/passwd.- How does the attacker get the file back?
They upload it as an attachment to a page or issue of their choosing, then call
download_attachment, which returns the bytes base64-encoded.
References
Read for this analysis:
How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. The analysis is written by an AI model from the sources listed above and checked by automated rules before it is published. Check versions against the vendor's advisory before you act. Methodology
More Other MCP servers and tools vulnerabilities
All Other MCP servers and tools entriesCVE-2026-77361
obsidian-tc : Symlink read-ACL scope bypass via lexical path checks
medium4.7Oct 23, 2026CVE-2026-114126
Storybook dev server vulnerable to code injection from the local network
high8.7Oct 22, 2026CVE-2026-113731
djust: Arbitrary absolute-path file read in the find_handlers_for_template MCP tool
low3.3Oct 21, 2026CVE-2026-114125
Storybook: Missing origin validation in Storybook preview allows code injection from malicious websites
critical9.4Oct 21, 2026CVE-2026-111770
MCP TypeScript server SDK: Shared transport or server instances delivered one HTTP client's messages to another
high7.7Oct 20, 2026GHSA-953h-535j-jg2v
agent-router: MCP session resume does not verify the embedded anti-hijacking subject; default Helm seed makes session IDs forgeable
medium6.8Oct 19, 2026
