FlawOpen

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

● CVE-2026-77244 · CVSS 10.0[1] · 严重
安全研究 · FlawOpen

CVE-2026-77244:mcp-atlassian 未认证 HTTP 工具访问

CVE-2026-77244 允许未认证调用者访问社区项目 mcp-atlassian 的 HTTP 工具处理程序;这些处理程序可能回退使用运营者环境中配置的 Jira 或 Confluence 凭据。主要修复版本为 0.22.0;SSE 用户还需升级到 0.23.1 或更高版本,以修复另一项相关传输漏洞。[1], [4], [5], [6]

CVSS 向量CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N[1]
💡 通俗易懂的原理解析 (ELI5)

前台本应先检查访客证件,再打开员工专用门。旧流程在没有证件时会借出前台的万能钥匙。这个缺陷把两个缺失的检查连在一起:HTTP 请求没有经过用户身份验证就能到达工具,而工具又能使用运营者共享的 Atlassian 凭据。修复会拒绝未认证 HTTP 请求,并要求显式启用凭据回退。[1], [3]

核心概念与专有名词

MCP 传输层
在客户端和服务器之间承载 Model Context Protocol 请求的通道。本 CVE 影响 mcp-atlassian 的 HTTP 传输;该公告说明 stdio 不受影响。[1], [4]
全局凭据回退
请求没有自己的用户身份时,使用服务器环境中配置的 Jira 或 Confluence 凭据。远程可访问的 HTTP 部署可能因此把匿名请求变成运营者身份的操作。[1], [4]
认证边界
服务器端必须在请求进入受保护工具处理程序前确认调用者身份。网络可达、非空 token 字符串或假定可信的代理本身都不能证明身份。[1], [7]
CWE-287
认证不当:应用在授予访问权限前未充分证明调用者声称的身份。[1], [7]
CWE-303
令牌验证器错误实现了身份验证:它接受任何非空令牌,却不验证令牌是否有效。[1], [9]
CWE-862
HTTP 请求无需经过要求验证用户身份的授权检查,就可能到达特权工具处理程序。[1], [10]

框架映射

根本原因剖析 (Root Cause)

GitHub 安全公告描述的是社区项目 mcp-atlassian 中的攻击链,并非 Atlassian 产品漏洞。在 0.22.0 之前,HTTP 中间件可能把没有用户身份的请求传给工具处理程序。如果部署从环境变量读取运营者凭据,JiraFetcher 或 ConfluenceFetcher 就可能回退使用这些全局凭据。公告还指出,不透明 token 验证器会接受任何非空字符串;这并不能证明调用者的真实身份。安全边界必须同时保护请求身份和凭据选择:缺失或未验证的用户绝不能继承运营者的高权限凭据。0.22.0 修复会对未认证的 streamable-HTTP MCP POST 返回 HTTP 401,并在 HTTP 上下文中阻止全局凭据回退,除非单用户部署显式设置 ALLOW_GLOBAL_CRED_FALLBACK=true。stdio 行为不变。另有 GHSA-5j8j-256g-vvp5 描述 SSE 路径匹配错误,并在 0.23.1 修复;它不是 CVE-2026-77244。SSE 部署应更新到 0.23.1 或更高版本,不能把 CVE 的 0.22.0 修复误认为也覆盖了另一公告。公告未确认存在实际利用;本文不声称发生过真实入侵。 该 CVE 公告将此链中的身份验证、令牌校验和授权缺陷分别关联到 CWE-287、CWE-303 和 CWE-862。 该安全公告将报告者列为 crazydude123。[1], [3], [4], [5], [6], [7], [9], [10]

攻击执行流程分解

步骤 1

MCP HTTP 端点可被访问

部署通过 HTTP 运行社区版 mcp-atlassian,未认证方可以访问其传输层。仅使用 stdio 的部署不属于本 CVE 影响路径。[1]

步骤 2

请求在用户身份未验证时到达工具

在 0.22.0 之前,没有用户身份的 HTTP 请求可能通过中间件,而不是在传输边界被拒绝。公告还指出,非空字符串不会被独立验证为真实身份。[1], [3]

步骤 3

工具选择运营者共享凭据

如果没有用户身份,而服务器环境配置了 Jira 或 Confluence 凭据,fetcher 可能使用全局凭据。该请求随后可行使运营者启用的工具权限;实际影响取决于账户权限和配置。[1], [3]

步骤 4

在传输边界拒绝,并在凭据选择时默认拒绝

0.22.0 会对未认证的 streamable-HTTP 请求返回 HTTP 401,并在 HTTP 上下文中阻止全局回退,除非显式启用。SSE 应安装 0.23.1 或更高版本,因为该版本修复了另一个路径匹配问题。[1], [4], [5], [6]

源代码对比:漏洞与安全实现

这是对控制流程的精简表示,不是完整函数的逐字副本。上游补丁在传输边界添加 HTTP 401,并在 HTTP 上下文返回全局 fetcher 前增加第二道检查;绕过两道保护都需要显式配置 ALLOW_GLOBAL_CRED_FALLBACK。[1], [3], [4]

存在漏洞的实现
# 受影响控制流的简化表示。
async def handle_request(scope, ctx):
    user_identity = scope.get("state", {}).get("user_atlassian_auth_type")
    # 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)
    # 回退使用环境配置中的操作员凭据。
    return fetcher_from_config(global_config)
加固后的安全修复
# 已合并到 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)

工程与系统安全加固清单

参考来源