CVE-2026-77261: MCP Atlassian SSRF Redirect Protection Missing For Vulnerability

HIGH
Advisory Identifier: GHSA-6529-c226-h328
CVSS 7.1
CWE-918
Published
Advisory Summary

CVE-2026-77261 is a HIGH (CVSS 7.1) ssrf redirect protection missing for vulnerability (CWE-918: Server-Side Request Forgery (SSRF)) affecting MCP Atlassian libraries in the PyPI ecosystem. The issue involves ssrf redirect protection missing for basic-auth and oauth authentication branches. Remediation is available by upgrading affected packages to version 0.22.0.

CVE-2026-77261 at a Glance

CVE Identifier CVE-2026-77261
GHSA Identifier GHSA-6529-c226-h328
Severity HIGH
CVSS v3.1 Base Score 7.1
CWE Classification CWE-918: Server-Side Request Forgery (SSRF)
Affected Product MCP Atlassian
Package Ecosystem PyPI
Published Date
Last Updated

Security Impact

CVSS: 7.1

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:N).

Attack Vector Network (AV:N)
Attack Complexity High (AC:H)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Changed (S:C)
Confidentiality High (C:H)
Integrity Low (I:L)
Availability None (A:N)

How to Fix CVE-2026-77261

To remediate this vulnerability, upgrade all affected MCP Atlassian dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

mcp-atlassian fixed: 0.22.0
pip install mcp-atlassian>=0.22.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show mcp-atlassian

How to Check if You Are Affected

To determine whether your Python environment is affected by CVE-2026-77261, inspect your installed packages using pip:

pip show mcp-atlassian

Analyze the terminal output to locate any version of MCP Atlassian in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.22.0), your application is affected.

Note: The pip show mcp-atlassian command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-918: Server-Side Request Forgery (SSRF), where the web server receives a url or similar request from an upstream component and retrieves the contents of this url, but it does not sufficiently ensure that the request is being sent to the expected destination. In MCP Atlassian, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary `_make_ssrf_safe_hook()` blocks HTTP redirects to private/internal IPs by validating the `Location` header before the client follows a `3xx` response. The problem is that this hook is only attached in one of three authentication branches — the header-PAT path. Basic auth and OAuth branches skip it entirely, so if the connected Atlassian server returns a redirect to something like `http://169.254.169.254/`, the `requests` session follows it without complaint. This is an incomplete fix for GHSA-7r34-79r5-rcc9. The hook works fine when it's there — it just isn't there for most production auth configurations. ### Details In `src/mcp_atlassian/servers/dependencies.py`, three branches construct a fetcher and call `_create_and_validate()`. Only Branch 1 passes `attach_ssrf_hook=True`: ```python # Branch 1 (header PAT) — hook attached return _create_and_validate(request, spec, header_config, "header_pat", attach_ssrf_hook=True) # Branch 2 (basic auth) — hook missing return _create_and_validate(request, spec, user_config, "basic", user_email=user_email) # Branch 3 (OAuth/PAT) — hook missing return _create_and_validate(request, spec, user_config, "oauth_pat", user_email=user_email) ``` `attach_ssrf_hook` defaults to `False`, so branches 2 and 3 silently skip the protection. The hook itself (`_make_ssrf_safe_hook`) is straightforward — it checks `response.is_redirect`, grabs the `Location` header, and calls `validate_url_for_ssrf()` to reject private IPs. It works correctly when present. Typical attack flow: 1. Attacker controls or compromises an Atlassian instance (Cloud or Server) 2. MCP server connects using basic auth or OAuth credentials (most production setups) 3. Atlassian returns `302 Location: http://169.254.169.254/latest/meta-data/iam/security-credentials/` 4. The unprotected session follows the redirect 5. AWS IAM credentials (or other internal service data) are returned to the attacker ### PoC Tested on commit `d8bc786` (v0.21.1). No real credentials needed. ```python from unittest.mock import MagicMock import requests from mcp_atlassian.servers.dependencies import _make_ssrf_safe_hook from mcp_atlassian.utils.urls import validate_url_for_ssrf from mcp_atlassian.jira import JiraFetcher from mcp_atlassian.jira.config import JiraConfig config = JiraConfig( url="https://attacker.atlassian.net", auth_type="basic", username="victim@example.com", api_token="victim-token", ) fetcher = JiraFetcher(config=config) session = fetcher.jira._session hooks = session.hooks.get("response", []) print("hooks on basic-auth session:", [h.__name__ for h in hooks] or "none") fake_redirect = MagicMock(spec=requests.Response) fake_redirect.is_redirect = True fake_redirect.headers = {"Location": "http://169.254.169.254/latest/meta-data/"} blocked = False for h in hooks: try: h(fake_redirect) except ValueError as e: blocked = True print("blocked:", e) if not blocked: print("redirect to 169.254.169.254 not blocked on basic-auth session") # show header-PAT branch does block it hook = _make_ssrf_safe_hook(validate_url_for_ssrf) try: hook(fake_redirect) except ValueError as e: print("header-PAT branch blocks:", e) ``` Output: <img width="2490" height="214" alt="image" src="https://github.com/user-attachments/assets/c7d9d7e2-4c37-4abd-95a3-4ddd9f6bd735" /> ``` $ uv run python3 /tmp/test.py hooks on basic-auth session: none redirect to 169.254.169.254 not blocked on basic-auth session header-PAT branch blocks: Redirect blocked (SSRF): Blocked IP address: 169.254.169.254 (non-global) ``` ### Impact Basic auth and OAuth cover most production Atlassian Cloud deployments, so this affects the majority of HTTP-mode multi-user setups. An attacker with control over the Atlassian server can redirect MCP server requests to internal infrastructure — cloud metadata endpoints, internal Kubernetes API, databases, or any service reachable from the MCP server's network. The fix is one line per affected branch: pass `attach_ssrf_hook=True` to `_create_and_validate()` in branches 2 and 3, the same way branch 1 already does.

CVE-2026-77261 Affected MCP Atlassian Versions

1 component(s)
Fixed Versions:
0.22.0
Product / Package Ecosystem Affected Versions Fixed Version
mcp-atlassian
PyPI
< 0.22.0
0.22.0

References

Frequently Asked Questions

What is CVE-2026-77261?
CVE-2026-77261 is a security vulnerability in MCP Atlassian involving SSRF redirect protection missing for basic-auth and OAuth authentication branches under CWE-918: Server-Side Request Forgery (SSRF).
Which MCP Atlassian versions are affected?
Affected versions include releases prior to 0.22.0 across affected packages: mcp-atlassian.
What version fixes CVE-2026-77261?
Upgrading to 0.22.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is mcp-atlassian affected?
Yes, mcp-atlassian is affected in releases prior to 0.22.0. Upgrade your dependency to 0.22.0 or later.
What is the CVSS score of CVE-2026-77261?
CVE-2026-77261 has a CVSS v3.1 base score of 7.1 (HIGH) with vector string CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:N.
What CWE is associated with CVE-2026-77261?
CVE-2026-77261 is classified under CWE-918: Server-Side Request Forgery (SSRF) (The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.).
How can I check PyPI dependencies for CVE-2026-77261?
Run the dependency tree command: 'pip show mcp-atlassian'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-6529-c226-h328",
  "modified" : "2026-09-22T20:35:13Z",
  "published" : "2026-09-22T20:35:13Z",
  "aliases" : [ "CVE-2026-77261" ],
  "summary" : "MCP Atlassian: SSRF redirect protection missing for basic-auth and OAuth authentication branches",
  "details" : "### Summary\n\n`_make_ssrf_safe_hook()` blocks HTTP redirects to private/internal IPs by validating the `Location` header before the client follows a `3xx` response. The problem is that this hook is only attached in one of three authentication branches — the header-PAT path. Basic auth and OAuth branches skip it entirely, so if the connected Atlassian server returns a redirect to something like `http://169.254.169.254/`, the `requests` session follows it without complaint.\n\nThis is an incomplete fix for GHSA-7r34-79r5-rcc9. The hook works fine when it's there — it just isn't there for most production auth configurations.\n\n### Details\n\nIn `src/mcp_atlassian/servers/dependencies.py`, three branches construct a fetcher and call `_create_and_validate()`. Only Branch 1 passes `attach_ssrf_hook=True`:\n\n```python\n# Branch 1 (header PAT) — hook attached\nreturn _create_and_validate(request, spec, header_config, \"header_pat\",\n                             attach_ssrf_hook=True)\n\n# Branch 2 (basic auth) — hook missing\nreturn _create_and_validate(request, spec, user_config, \"basic\",\n                             user_email=user_email)\n\n# Branch 3 (OAuth/PAT) — hook missing\nreturn _create_and_validate(request, spec, user_config, \"oauth_pat\",\n                             user_email=user_email)\n```\n\n`attach_ssrf_hook` defaults to `False`, so branches 2 and 3 silently skip the protection. The hook itself (`_make_ssrf_safe_hook`) is straightforward — it checks `response.is_redirect`, grabs the `Location` header, and calls `validate_url_for_ssrf()` to reject private IPs. It works correctly when present.\n\nTypical attack flow:\n\n1. Attacker controls or compromises an Atlassian instance (Cloud or Server)\n2. MCP server connects using basic auth or OAuth credentials (most production setups)\n3. Atlassian returns `302 Location: http://169.254.169.254/latest/meta-data/iam/security-credentials/`\n4. The unprotected session follows the redirect\n5. AWS IAM credentials (or other internal service data) are returned to the attacker\n\n### PoC\n\nTested on commit `d8bc786` (v0.21.1). No real credentials needed.\n\n```python\nfrom unittest.mock import MagicMock\nimport requests\n\nfrom mcp_atlassian.servers.dependencies import _make_ssrf_safe_hook\nfrom mcp_atlassian.utils.urls import validate_url_for_ssrf\nfrom mcp_atlassian.jira import JiraFetcher\nfrom mcp_atlassian.jira.config import JiraConfig\n\nconfig = JiraConfig(\n    url=\"https://attacker.atlassian.net\",\n    auth_type=\"basic\",\n    username=\"victim@example.com\",\n    api_token=\"victim-token\",\n)\nfetcher = JiraFetcher(config=config)\nsession = fetcher.jira._session\n\nhooks = session.hooks.get(\"response\", [])\nprint(\"hooks on basic-auth session:\", [h.__name__ for h in hooks] or \"none\")\n\nfake_redirect = MagicMock(spec=requests.Response)\nfake_redirect.is_redirect = True\nfake_redirect.headers = {\"Location\": \"http://169.254.169.254/latest/meta-data/\"}\n\nblocked = False\nfor h in hooks:\n    try:\n        h(fake_redirect)\n    except ValueError as e:\n        blocked = True\n        print(\"blocked:\", e)\n\nif not blocked:\n    print(\"redirect to 169.254.169.254 not blocked on basic-auth session\")\n\n# show header-PAT branch does block it\nhook = _make_ssrf_safe_hook(validate_url_for_ssrf)\ntry:\n    hook(fake_redirect)\nexcept ValueError as e:\n    print(\"header-PAT branch blocks:\", e)\n```\n\nOutput:\n\n<img width=\"2490\" height=\"214\" alt=\"image\" src=\"https://github.com/user-attachments/assets/c7d9d7e2-4c37-4abd-95a3-4ddd9f6bd735\" />\n\n```\n$ uv run python3 /tmp/test.py\nhooks on basic-auth session: none\nredirect to 169.254.169.254 not blocked on basic-auth session\nheader-PAT branch blocks: Redirect blocked (SSRF): Blocked IP address: 169.254.169.254 (non-global)\n```\n\n### Impact\n\nBasic auth and OAuth cover most production Atlassian Cloud deployments, so this affects the majority of HTTP-mode multi-user setups. An attacker with control over the Atlassian server can redirect MCP server requests to internal infrastructure — cloud metadata endpoints, internal Kubernetes API, databases, or any service reachable from the MCP server's network.\n\nThe fix is one line per affected branch: pass `attach_ssrf_hook=True` to `_create_and_validate()` in branches 2 and 3, the same way branch 1 already does.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "mcp-atlassian"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.22.0"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/sooperset/mcp-atlassian/security/advisories/GHSA-6529-c226-h328"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-77261"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/sooperset/mcp-atlassian/pull/1448"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/sooperset/mcp-atlassian/commit/b041733473f95119dd539542a43c280737a8e460"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/sooperset/mcp-atlassian"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/sooperset/mcp-atlassian/releases/tag/v0.22.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-918" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-09-22T20:35:13Z",
    "nvd_published_at" : "2026-09-22T18:17:18Z"
  }
}