PT-2026-105836 · Pypi · Mcp-Attlasian
Published
2026-10-01
·
Updated
2026-10-01
CVSS v3.1
8.8
High
| Vector | AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
Summary
ENABLED TOOLS and TOOLSETS filters are enforced at tools/list time only. tools/call dispatches from the full unfiltered tool registry (73 tools). Any user with access to the server endpoint that knows a tool name can invoke it directly. Tool names are not secret since mcp-atlassian is open source. Any direct JSON-RPC call bypasses the restriction entirely.READ ONLY MODE is not affected: it has dual enforcement at list time ( list tools mcp) and call time @check write access decorator. The developers applied the correct pattern to READ ONLY MODE but not to ENABLED TOOLS or toolsets - confirming this is an implementation oversight.Impact
Any user with access to the MCP server's HTTP endpoint can invoke any of the 73 registered tools regardless of
ENABLED TOOLS or TOOLSETS configuration - including write and delete operations on Jira issues, Confluence pages, etc. Operators deploying mcp-atlassian via Streamable HTTP rely on ENABLED TOOLS to enforce least-privilege access; the bypass invalidates that model entirely.The security impact concentrates in multi-user / HTTP-transport deployments, where the tool filter is a trust boundary between clients. In a single-user stdio deployment there is no second principal to defend against.
Details
In
src/mcp atlassian/servers/main.py, AtlassianMCP overrides list tools mcp and applies the TOOLSETS and ENABLED TOOLS filters before returning the tool list to clients. The call tool mcp handler is not overridden. FastMCP's default call tool mcp resolves the tool from the local tool manager / mounted servers, the full unfiltered inventory, so the filters never apply at call time.Proof of Concept
All calls are issued against the HTTP transport, with
ENABLED TOOLS=jira search configured - only jira search should be reachable.Step 1 - negative control: tools/list correctly filters by ENABLED TOOLS:
req → tools/list
← { "tools": [ { "name": "jira search" } ] } # only 1 tool; jira get issue / jira create issue absentStep 2 - confidentiality bypass: tools/call dispatches jira get issue despite its exclusion from the list:
req → tools/call jira get issue { "issue key": "SEC-1" }
← { ... issue fields (summary, status, ...) ... } # executed; not blockedStep 3 - integrity bypass: tools/call dispatches the write tool jira create issue:
req → tools/call jira create issue
{ "project key": "SEC", "summary": "[PoC] ENABLED TOOLS bypass", "issue type": "Task" }
← { ... "key": "SEC-<n>" ... } # issue created despite ENABLED TOOLS=jira searchStep 1 proves the filter exists and is enforced at list time, so Steps 2–3 are a genuine authorization bypass, not an open/unconfigured endpoint. The same result holds with TOOLSETS=jira read configured: write tools are absent from tools/list yet execute via tools/call.
Local reproduction
Extract
enabled tools bypass tool authorization.zip:# Fill Atlassian credentials in docker-compose.yml (ENABLED TOOLS=jira search is preset);
# ensure issue SEC-1 exists, or update the project/issue key in poc.sh
docker compose up -d # mcp-atlassian, streamable-http, 0.0.0.0, ENABLED TOOLS=jira search
./poc.sh # exits 0 on success
docker compose down -vRequires Docker, curl, jq, and an Atlassian Cloud site with a Jira project (free tier works). The script runs the three steps above: it confirms tools/list returns only jira search, then dispatches the excluded jira get issue (read) and jira create issue (write) via tools/call. The test issue it creates is deleted automatically on exit.
Credit
Discovered by Francisco Rosales of Manifold Security
Fix
Found an issue in the description? Have something to add? Feel free to write us 👾
Related Identifiers
Affected Products
Mcp-Attlasian