NewApp Monitoring is liveSign up free
AgentbeamBeta
AI agent vulnerability · Other MCP servers and tools

CVE-2026-77249: MCP Atlassian: Incomplete fix for GHSA-7r34-79r5-rcc9: redirect-based SSRF via unhooked requests session in Jira user-permission lookup

mediumCVSS 3.1 5.3GHSA-v9m3-wfh8-5646

One request path in mcp-atlassian before 0.22.0, the Jira assignee permission lookup, uses a bare `requests.get` that skips the redirect guard added for CVE-2026-27826. An attacker-run public server can redirect that call to an internal address. The SSRF is blind. Fixed in 0.22.0.

Published Sep 22, 2026 · Analysis Oct 22, 2026

What an attacker can do

The earlier fix for GHSA-7r34-79r5-rcc9 validated the X-Atlassian-Jira-Url header and attached _make_ssrf_safe_hook to the fetcher's session, f.jira._session. But JiraUserMixin._lookup_user_by_permissions in jira/users.py calls module-level requests.get against /rest/api/2/user/permission/search. That call does not use the hooked session and follows redirects by default. The equivalent call in development.py correctly uses self.jira._session.get.

The attack: in HTTP multi-tenant mode, which binds 0.0.0.0, the attacker sets the Jira URL header to a public server they run. It passes validate_url_for_ssrf(). That server answers the user search with an empty list, then answers the permission search with a 302 whose Location points at 169.254.169.254 or any internal host and port. The attacker triggers it with a tool that resolves an assignee, such as jira_create_issue or jira_update_issue. Credential validation also runs against the attacker's server, so no real Atlassian credentials are needed.

The result is a blind GET to internal hosts: port discovery, reachability of metadata endpoints, and internal endpoints that act on GET. The body is reflected only if the internal service returns JSON shaped like {"users": [...]}. This is weaker than the parent issue.

Who is affected

mcp-atlassian below 0.22.0, reported against 0.21.1, in HTTP or SSE multi-tenant mode where clients provide the Jira URL through headers. Stdio deployments with a fixed, trusted Jira URL are not exposed to header-supplied hosts.

pip show mcp-atlassian

mcp-atlassian

Ecosystem
PyPI
Affected
< 0.22.0
Fixed in
0.22.0
Check
pip show mcp-atlassian

How to fix it

Upgrade to 0.22.0:

pip install --upgrade mcp-atlassian==0.22.0

The reporter's suggested fix is to route the call through self.jira._session.get(...), which carries the hook and the authentication, and to audit for any other bare requests.* or httpx.* call that uses self.config.url. As interim protection, do not expose the HTTP transport to untrusted clients and block egress from the host to internal and link-local ranges.

How to tell if you were hit

Look for outbound requests from the MCP process to your internal ranges or 169.254.169.254, following a request to a public host that answered with a 302. Review MCP logs for jira_create_issue or jira_update_issue calls with assignee values that cannot be matched, coming from clients whose X-Atlassian-Jira-Url is not your Jira domain. Egress and DNS logs from the host will show the public redirecting domain.

Original advisory

From the GitHub Advisory Database (CC BY 4.0).

Summary

The fix for the SSRF vulnerability tracked as GHSA-7r34-79r5-rcc9 / CVE-2026-27826 is incomplete. That fix added two defenses: validate_url_for_ssrf() on the per-request X-Atlassian-Jira-Url / X-Atlassian-Confluence-Url headers (blocking a directly-internal base URL), and a redirect-validation hook (_make_ssrf_safe_hook) attached to the fetcher's HTTP session so that an attacker-controlled public host cannot redirect outbound requests to an internal address.

However, one outbound request path does not go through the hooked session. JiraUserMixin._lookup_user_by_permissions issues its request with the module-level requests.get instead of self.jira._session.get, so the redirect-validation hook never runs for it. An unauthenticated attacker (in the HTTP / multi-tenant transport mode that binds 0.0.0.0 with no credentials) can therefore set a public base URL that passes validate_url_for_ssrf(), then have their own server return an HTTP redirect to an internal address. The bare requests.get follows that redirect with no validation, resulting in a blind server-side request to an arbitrary internal host and port.

Affected component

src/mcp_atlassian/jira/users.py, method _lookup_user_by_permissions (the requests.get(...) call):

url = f"{self.config.url}/rest/api/2/user/permission/search" params = {"query": username, "permissions": "BROWSE"} ... response = requests.get( # module-level requests, NOT self.jira._session url, params=params, auth=auth, headers=headers, verify=self.config.ssl_verify, )

For comparison, the equivalent non-standard-endpoint call in src/mcp_atlassian/jira/development.py correctly uses the hooked session (self.jira._session.get(...)), and the SSRF redirect hook is attached only to that session in src/mcp_atlassian/servers/dependencies.py (get_session=lambda f: f.jira._session). The bare requests.get in users.py is the one outbound path the hook does not cover.

Details — why the existing defenses do not apply here

  1. self.config.url is attacker-controlled in the header-PAT branch of _get_fetcher (dependencies.py): header_config = spec.config_class(url=url_header_val, auth_type="pat", personal_token=token_header_val, ...).
  2. The middleware validates that header URL with validate_url_for_ssrf() before storing it, so it must resolve to a public address. The attacker simply points it at a public server they control — this passes validation.
  3. Credential validation (_create_and_validate → spec.validate_fn) runs against that same attacker-controlled server, so it returns success and no real Atlassian credentials are required.
  4. The redirect-validation hook is attached to f.jira._session. _lookup_user_by_permissions does not use that session — it uses bare requests.get, which follows redirects (allow_redirects=True by default) with no SSRF check.

Proof of Concept

Preconditions: the server is running in HTTP transport (streamable-http or sse) multi-tenant mode, as described in the GHSA-7r34-79r5-rcc9 advisory (binds 0.0.0.0, per-request header auth, no server-side credentials).

  1. Attacker stands up a public HTTP server http://attacker.example that:
  2. responds to GET /rest/api/2/user/search (and the atlassian client's user-find call) with 200 [] — an empty user list, forcing the direct-lookup fallthrough;
  3. responds to GET /rest/api/2/user/permission/search with 302 Location: http://169.254.169.254/latest/meta-data/ (or any internal host:port).
  4. Attacker sends a tool call to the MCP HTTP endpoint with headers:
  5. X-Atlassian-Jira-Url: http://attacker.example
  6. X-Atlassian-Jira-Personal-Token: anything and invokes a tool that resolves an assignee — e.g. jira_create_issue / jira_update_issue with assignee set to a value that the direct lookup cannot match.
  7. Flow: _get_account_id → _lookup_user_directly returns None (attacker returned []) → _lookup_user_by_permissions → requests.get("http://attacker.example/rest/api/2/user/permission/search?...") → attacker server returns 302 → bare requests follows the redirect to http://169.254.169.254/....

The server makes an outbound GET to the internal target, confirming SSRF.

Impact

Blind, unauthenticated server-side request forgery from the mcp-atlassian host. An attacker who can reach the HTTP transport endpoint can cause the server to issue GET requests to arbitrary internal hosts and ports (internal service reachability and port discovery, triggering of internal GET-actuated endpoints, reachability of cloud metadata endpoints). The response body is not reflected to the attacker except in the narrow case where an internal service returns a JSON object shaped like {"users": [...]}, so this is primarily a blind SSRF: weaker than the original CVE-2026-27826 (no general internal data exfiltration), but the redirect-based internal-reachability that GHSA-7r34-79r5-rcc9 intended to close remains exploitable through this code path in the latest release (v0.21.1).

Suggested Remediation

Route the request through the hooked session instead of the module-level requests, mirroring development.py:

response = self.jira._session.get( url, params=params, verify=self.config.ssl_verify, )

(The session already carries the appropriate authentication, so the manual auth / Authorization handling can be dropped.) More generally, auditing for any remaining bare requests.* / httpx.* calls that use self.config.url and routing them through the SSRF-hooked session would prevent recurrence.

Coordinated Disclosure

This appears to be an incomplete fix for GHSA-7r34-79r5-rcc9 (CVE-2026-27826). If you agree, I would kindly ask you to consider requesting a CVE ID for this residual instance through this repository's Security Advisory "Request CVE ID" workflow once confirmed, so that downstream users and distributions can track the additional fix. The severity here is lower than the parent advisory — it is a blind, redirect-only SSRF gated on the HTTP multi-tenant deployment mode — so a Medium rating seems appropriate, and I defer to your judgment on the final score. Thank you very much for your time and for your work on this project.

Credited to Yunkaiwjs.

Questions

Is this the same as GHSA-7r34-79r5-rcc9?

It is a residual instance of it. That fix covered the header URL and the session hook, but this lookup used a separate unhooked requests call.

Can the attacker read the internal response?

Mostly no. It is a blind SSRF, except where an internal service returns a JSON object shaped like users: [...].

Do they need Atlassian credentials?

No. Validation runs against the attacker's own server, which returns success.

Why is the severity medium?

The flaw is blind, redirect-only and limited to HTTP multi-tenant deployments. The CVSS 3.1 score is 5.3.

References

How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. The analysis is written by an AI model from the sources listed above and checked by automated rules before it is published. Check versions against the vendor's advisory before you act. Methodology

More Other MCP servers and tools vulnerabilities

All Other MCP servers and tools entries