FlawOpen

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

● CVE-2026-77244 · CVSS 10.0[1] · Critique
Recherche · FlawOpen

CVE-2026-77244 : accès HTTP non authentifié à mcp-atlassian

CVE-2026-77244 permettait à des appels non authentifiés d’atteindre les gestionnaires HTTP du projet communautaire mcp-atlassian, qui pouvaient utiliser les identifiants Jira ou Confluence configurés dans l’environnement de l’opérateur. Le correctif principal est arrivé en 0.22.0 ; les utilisateurs de SSE doivent passer à 0.23.1 ou ultérieur pour une faille de transport distincte.[1], [4], [5], [6]

Vecteur CVSSCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N[1]
💡 Explication en Langage Simple (ELI5)

L’accueil doit vérifier le badge d’un visiteur avant d’ouvrir une porte réservée au personnel. Dans l’ancien flux, sans badge, l’accueil prêtait son passe-partout. Le défaut associait deux contrôles absents : une requête HTTP pouvait atteindre les outils sans identité vérifiée, puis ceux-ci pouvaient utiliser les identifiants Atlassian partagés de l’opérateur. Le correctif rejette les requêtes HTTP non authentifiées et rend ce recours aux identifiants explicite.[1], [3]

Concepts Clés et Termes

Transport MCP
Canal qui transporte les requêtes Model Context Protocol entre un client et un serveur. Cette CVE concerne le transport HTTP de mcp-atlassian ; l’avis ne touche pas stdio.[1], [4]
Repli sur les identifiants globaux
Utilisation des identifiants Jira ou Confluence de l’environnement du serveur lorsqu’une requête n’a pas d’identité par utilisateur. Sur un HTTP accessible à distance, une requête anonyme peut alors agir comme l’opérateur.[1], [4]
Frontière d’authentification
Contrôle côté serveur qui établit l’identité avant qu’une requête n’atteigne les gestionnaires protégés. L’accès réseau, un jeton non vide ou une confiance supposée envers un proxy ne prouvent pas seuls une identité.[1], [7]
CWE-287
Authentification incorrecte : l’application ne prouve pas suffisamment l’identité revendiquée avant d’accorder l’accès.[1], [7]
CWE-303
Le vérificateur de jetons implémente mal l’authentification : il accepte tout jeton non vide sans vérifier sa validité.[1], [9]
CWE-862
La requête HTTP pouvait atteindre des gestionnaires d’outils privilégiés sans contrôle d’autorisation exigeant une identité utilisateur vérifiée.[1], [10]

Correspondances de référentiels

Analyse de Cause Racine

L’avis GitHub décrit une chaîne dans le projet communautaire mcp-atlassian, pas une vulnérabilité d’un produit Atlassian. Avant 0.22.0, le middleware HTTP pouvait laisser une requête sans identité utilisateur atteindre les gestionnaires d’outils. Si le déploiement utilisait les identifiants de l’opérateur issus des variables d’environnement, JiraFetcher ou ConfluenceFetcher pouvait les reprendre. L’avis décrit aussi un vérificateur de jetons opaques qui acceptait toute chaîne non vide ; cela ne prouve pas l’identité réelle de l’appelant. La frontière doit protéger ensemble l’identité de la requête et le choix des identifiants : un utilisateur absent ou non vérifié ne doit jamais hériter de l’identifiant privilégié de l’opérateur. Le correctif 0.22.0 renvoie HTTP 401 aux requêtes MCP streamable-HTTP non authentifiées et bloque le repli global en contexte HTTP, sauf configuration explicite de ALLOW_GLOBAL_CRED_FALLBACK=true pour un déploiement mono-utilisateur. Le comportement stdio reste inchangé. Séparément, GHSA-5j8j-256g-vvp5 décrit un défaut de correspondance des chemins SSE corrigé en 0.23.1 ; il ne s’agit pas de CVE-2026-77244. Passez les déploiements SSE à 0.23.1 ou ultérieur et ne supposez pas que le correctif CVE 0.22.0 règle aussi cet autre avis. L’avis ne confirme pas d’exploitation ; cet article n’affirme pas qu’une intrusion réelle a eu lieu. L’avis CVE attribue les CWE-287, CWE-303 et CWE-862 aux défauts d’authentification, de vérification du jeton et d’autorisation de cette chaîne. L’avis attribue le signalement à crazydude123.[1], [3], [4], [5], [6], [7], [9], [10]

Déroulement de l'Attaque Étape par Étape

Étape 1

Un endpoint HTTP MCP est accessible

Le déploiement exécute le serveur communautaire mcp-atlassian en HTTP et une partie non authentifiée peut atteindre son transport. Les déploiements stdio uniquement sont hors du chemin concerné par cette CVE.[1]

Étape 2

La requête atteint un outil sans utilisateur vérifié

Avant 0.22.0, une requête HTTP sans identité propre pouvait traverser le middleware au lieu d’être rejetée à la frontière du transport. L’avis note aussi qu’une chaîne non vide n’était pas vérifiée indépendamment comme identité.[1], [3]

Étape 3

L’outil choisit les identifiants partagés de l’opérateur

Sans identité propre et si le serveur possède des identifiants Jira ou Confluence dans son environnement, le fetcher peut utiliser les identifiants globaux. La requête peut alors exercer les permissions des outils activés pour l’opérateur ; l’impact exact dépend de ses droits et de la configuration.[1], [3]

Étape 4

Rejeter au transport et échouer en mode fermé lors du choix d’identifiants

La version 0.22.0 renvoie HTTP 401 aux requêtes streamable-HTTP non authentifiées et bloque le repli global en contexte HTTP sauf activation explicite. Pour SSE, installez 0.23.1 ou ultérieur, qui corrige le défaut distinct de correspondance de chemin.[1], [4], [5], [6]

Code Source : Vulnérable vs Sécurisé

Représentation condensée du flux, pas copie littérale des fonctions complètes. Le correctif amont ajoute HTTP 401 à la frontière du transport et une seconde protection avant de fournir le fetcher global en contexte HTTP ; les deux exigent l’option explicite ALLOW_GLOBAL_CRED_FALLBACK.[1], [3], [4]

IMPLÉMENTATION VULNÉRABLE
# Représentation simplifiée du flux de contrôle concerné.
async def handle_request(scope, ctx):
    user_identity = scope.get("state", {}).get("user_atlassian_auth_type")
    # L’absence d’identité n’était pas rejetée à la frontière HTTP.
    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)
    # Utilise les identifiants de l’opérateur configurés dans l’environnement en secours.
    return fetcher_from_config(global_config)
PATCH SÉCURISÉ ET ROBUSTE
# Représentation ciblée des protections intégrées dans la version 0.22.0.
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)

Liste de Contrôle de Sécurité pour l'Ingénierie

Sources