FlawOpen

flawopen.com/Teardowns/cve-2026-77244-mcp-atlassian-http-auth-bypass

● CVE-2026-77244 · CVSS 10.0[1] · Critical
FlawOpen Security Research

CVE-2026-77244: mcp-atlassian Unauthenticated HTTP Tool Access

CVE-2026-77244 let unauthenticated callers reach the community mcp-atlassian HTTP tool handlers, which could fall back to the operator's environment-configured Jira or Confluence credentials. The maintainer fixed this in 0.22.0; SSE users need 0.23.1 or later for a separate related transport flaw.[1], [4], [5], [6]

CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N[1]
💡 Plain English Explainer (ELI5)

A reception desk is supposed to check a visitor badge before opening a staff-only door. If no badge is present, the old workflow borrowed the receptionist's master key and opened the door anyway. The flaw joined two missing checks: HTTP requests could reach the tools without a verified user identity, and the tools could use the operator's shared Atlassian credentials. The fix rejects unauthenticated HTTP requests and makes that credential fallback opt-in.[1], [3]

Core Concepts & Subsystem Terms

MCP transport
The channel that carries Model Context Protocol requests between a client and server. This CVE concerns the mcp-atlassian HTTP transport; stdio is not affected by this advisory.[1], [4]
Global credential fallback
Using Jira or Confluence credentials configured in the server environment when a request has no per-user identity. In a remotely reachable HTTP deployment, this can turn an unauthenticated request into an action as the operator.[1], [4]
Authentication boundary
The server-side check that must establish a caller's identity before a request reaches protected tool handlers. Network reachability, a non-empty token string, or a trusted proxy assumption is not identity verification by itself.[1], [7]
CWE-287
Improper Authentication: the application does not adequately prove the identity claimed by an actor before granting access.[1], [7]
CWE-303
The token verifier implements authentication incorrectly: it accepts any non-empty token without checking that the token is valid.[1], [9]
CWE-862
The HTTP request could reach privileged tool handlers without an authorization check requiring a verified user identity.[1], [10]

Framework mappings

Root Cause Analysis

The GitHub security advisory describes a chain in community project mcp-atlassian, not an Atlassian product vulnerability. In affected versions before 0.22.0, the HTTP middleware could pass a request with no user identity to tool handlers. When the deployment used operator credentials from environment variables, JiraFetcher or ConfluenceFetcher could fall back to those global credentials. The advisory also documents an opaque token verifier that accepted any non-empty string; that behavior is not proof of a real caller identity. The security boundary must be the request identity and credential-selection logic together: a missing or unverified user must never inherit the operator's privileged credential. The merged 0.22.0 fix rejects unauthenticated streamable-HTTP MCP POSTs with HTTP 401 and refuses global credential fallback in HTTP context unless ALLOW_GLOBAL_CRED_FALLBACK=true is explicitly configured for a single-user deployment. Stdio behavior is unchanged. Separately, GHSA-5j8j-256g-vvp5 describes an SSE-path middleware mismatch fixed in 0.23.1; it is not CVE-2026-77244. Upgrade SSE deployments to 0.23.1 or later, and do not infer that the CVE's 0.22.0 patch also fixes that separate advisory. The advisory reports no confirmed exploitation status; this article does not claim a real-world breach. The CVE advisory lists CWE-287, CWE-303, and CWE-862 for the authentication, token-verification, and authorization failures in this chain. The advisory credits crazydude123 as the reporter.[1], [3], [4], [5], [6], [7], [9], [10]

Step-by-Step Attack Flow

Step 1

An HTTP MCP endpoint is reachable

The deployment runs the community mcp-atlassian server over HTTP and an unauthenticated party can reach its transport. Stdio-only deployments are outside this CVE's affected path.[1]

Step 2

The request reaches a tool without a verified user

Before 0.22.0, an HTTP request without a per-user identity could pass middleware instead of being rejected at the transport boundary. The advisory also notes that a non-empty opaque token was not independently verified as an identity.[1], [3]

Step 3

A tool selects shared operator credentials

If no per-user identity is present and the server has Jira or Confluence credentials in its environment, the fetcher may use those global credentials. The request can then exercise the operator's enabled tool permissions; the exact impact follows that account's privileges and configured tools.[1], [3]

Step 4

Reject at the transport and fail closed at credential selection

Version 0.22.0 returns HTTP 401 for unauthenticated streamable-HTTP requests and blocks global fallback in HTTP context unless explicitly opted in. For SSE, install 0.23.1 or later because its separate path-matching authentication flaw was fixed there.[1], [4], [5], [6]

Source Code: Flaw vs. Secure Implementation

These are condensed control-flow representations, not verbatim full functions. The upstream patch adds a transport-boundary 401 and a second guard before returning the global Jira/Confluence fetcher in HTTP context; both require the explicit ALLOW_GLOBAL_CRED_FALLBACK opt-in to bypass. The dual check prevents an unauthenticated request from reaching a tool and prevents a downstream identity gap from silently selecting the operator's credentials.[1], [3], [4]

Source excerpt: src/mcp_atlassian/servers/main.py and dependencies.py — HTTP authentication boundary and fetcher fallback

UNPATCHED FLAW
# Simplified representation of the affected control flow.
async def handle_request(scope, ctx):
    user_identity = scope.get("state", {}).get("user_atlassian_auth_type")
    # Missing identity was not rejected at the HTTP boundary.
    return await call_tool_handler(ctx, user_identity=user_identity)

def get_fetcher(user_identity, global_config):
    if user_identity:
        return fetcher_for_user(user_identity)
    # Falls back to operator credentials from environment configuration.
    return fetcher_from_config(global_config)
HARDENED SECURE PATCH
# Focused representation of the merged 0.22.0 safeguards.
async def handle_request(scope, ctx):
    user_identity = scope.get("state", {}).get("user_atlassian_auth_type")
    if is_mcp_http_post(scope) and not user_identity and not allow_global_fallback():
        return http_401("Authentication required")
    return await call_tool_handler(ctx, user_identity=user_identity)

def get_fetcher(user_identity, global_config, *, in_http_context):
    if user_identity:
        return fetcher_for_user(user_identity)
    if in_http_context and not allow_global_fallback():
        raise PermissionError("Refusing operator credentials for an unauthenticated HTTP request")
    return fetcher_from_config(global_config)

Engineering & System Hardening Checklist

Sources