CVE-2026-77249
MCP Atlassian: Incomplete fix for CVE-2026-27826: redirect-based SSRF via unhooked requests session in Jira user-permission lookup
MCP Atlassian is a Model Context Protocol (MCP) server for Atlassian products (Confluence and Jira). Prior to 0.22.0, JiraUserMixin._lookup_user_by_permissions uses the module-level requests.get function instead of the fetcher's protected session. A caller-controlled public Jira URL can redirect that unhooked request to an internal address, bypassing the redirect checks added for CVE-2026-27826. The advisory traces the vulnerable input and processing flow through JiraUserMixin._lookup_user_by_permissions, requests.get, self.jira._session.get, and _make_ssrf_safe_hook, which identify the affected entry points, controls, and code paths. This issue is fixed in version 0.22.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- Low
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
5.3
MCP Atlassian: Incomplete fix for CVE-2026-27826: redirect-based SSRF via unhooked requests session in Jira user-permission lookup
MCP Atlassian is a Model Context Protocol (MCP) server for Atlassian products (Confluence and Jira). Prior to 0.22.0, JiraUserMixin._lookup_user_by_permissions uses the module-level requests.get function instead of the fetcher's protected session. A caller-controlled public Jira URL can redirect that unhooked request to an internal address, bypassing the redirect checks added for CVE-2026-27826. The advisory traces the vulnerable input and processing flow through JiraUserMixin._lookup_user_by_permissions, requests.get, self.jira._session.get, and _make_ssrf_safe_hook, which identify the affected entry points, controls, and code paths. This issue is fixed in version 0.22.0.
- Record
CVE-2026-77249- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
EUVDEUVD-2026-84759
5.3
MCP Atlassian is a Model Context Protocol (MCP) server for Atlassian products (Confluence and Jira). Prior to 0.22.0, JiraUserMixin._lookup_user_by_permissions uses the module-level requests.get function instead of the fetcher's protected session. A caller-controlled public Jira URL can redirect that unhooked request to an internal address, bypassing the redirect checks added for CVE-2026-27826. The advisory traces the vulnerable input and processing flow through JiraUserMixin._lookup_user_by_permissions, requests.get, self.jira._session.get, and _make_ssrf_safe_hook, which identify the affected entry points, controls, and code paths. This issue is fixed in version 0.22.0.
- Record
EUVD-2026-84759- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-v9m3-wfh8-5646
5.3
MCP Atlassian: Incomplete fix for GHSA-7r34-79r5-rcc9: redirect-based SSRF via unhooked requests session in Jira user-permission lookup
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
- 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, ...).
- 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.
- 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.
- 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).
- Attacker stands up a public HTTP server http://attacker.example that:
- 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;
- 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).
- Attacker sends a tool call to the MCP HTTP endpoint with headers:
- X-Atlassian-Jira-Url: http://attacker.example
- 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.
- Flow: _get_account_id → _lookup_user_directly returns None (attacker returned []) → _lookup_user_by_permissions →…
- Record
GHSA-v9m3-wfh8-5646- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
NVD
5.3
MCP Atlassian is a Model Context Protocol (MCP) server for Atlassian products (Confluence and Jira). Prior to 0.22.0, JiraUserMixin._lookup_user_by_permissions uses the module-level requests.get function instead of the fetcher's protected session. A caller-controlled public Jira URL can redirect that unhooked request to an internal address, bypassing the redirect checks added for CVE-2026-27826. The advisory traces the vulnerable input and processing flow through JiraUserMixin._lookup_user_by_permissions, requests.get, self.jira._session.get, and _make_ssrf_safe_hook, which identify the affected entry points, controls, and code paths. This issue is fixed in version 0.22.0.
- Record
CVE-2026-77249- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSV
5.3
MCP Atlassian: Incomplete fix for CVE-2026-27826: redirect-based SSRF via unhooked requests session in Jira user-permission lookup
MCP Atlassian is a Model Context Protocol (MCP) server for Atlassian products (Confluence and Jira). Prior to 0.22.0, JiraUserMixin._lookup_user_by_permissions uses the module-level requests.get function instead of the fetcher's protected session. A caller-controlled public Jira URL can redirect that unhooked request to an internal address, bypassing the redirect checks added for CVE-2026-27826. The advisory traces the vulnerable input and processing flow through JiraUserMixin._lookup_user_by_permissions, requests.get, self.jira._session.get, and _make_ssrf_safe_hook, which identify the affected entry points, controls, and code paths. This issue is fixed in version 0.22.0.
- Record
CVE-2026-77249- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSVGHSA-v9m3-wfh8-5646
5.3
MCP Atlassian: Incomplete fix for GHSA-7r34-79r5-rcc9: redirect-based SSRF via unhooked requests session in Jira user-permission lookup
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
- 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, ...).
- 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.
- 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.
- 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).
- Attacker stands up a public HTTP server http://attacker.example that:
- 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;
- 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).
- Attacker sends a tool call to the MCP HTTP endpoint with headers:
- X-Atlassian-Jira-Url: http://attacker.example
- 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.
- Flow: _get_account_id → _lookup_user_directly returns None (attacker returned []) → _lookup_user_by_permissions →…
- Record
GHSA-v9m3-wfh8-5646- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSVPYSEC-2026-4100
5.3
MCP Atlassian: Incomplete fix for GHSA-7r34-79r5-rcc9: redirect-based SSRF via unhooked requests session in Jira user-permission lookup
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
- 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, ...).
- 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.
- 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.
- 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).
- Attacker stands up a public HTTP server http://attacker.example that:
- 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;
- 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).
- Attacker sends a tool call to the MCP HTTP endpoint with headers:
- X-Atlassian-Jira-Url: http://attacker.example
- 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.
- Flow: _get_account_id → _lookup_user_directly returns None (attacker returned []) → _lookup_user_by_permissions →…
- Record
PYSEC-2026-4100- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
mcp-atlassianPyPI |
before 0.22.0 | 0.22.0 |
mcp-atlassianPyPI |
before 0.22.0, plus listed versions 0.1.10.1.100.1.110.1.120.1.13 Show 45 moreShow less0.1.140.1.150.1.160.1.20.1.30.1.40.1.60.1.70.1.80.1.90.10.00.10.10.10.20.10.30.10.40.10.50.10.60.11.00.11.10.11.100.11.110.11.120.11.20.11.2a20.11.30.11.40.11.50.11.60.11.70.11.80.11.90.12.00.13.00.13.10.14.00.14.10.14.20.14.30.15.00.16.00.16.10.17.00.18.00.18.10.19.0 |
0.22.0 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-77249 is a medium vulnerability (CVSS 5.3) in Mcp-atlassian Mcp Atlassian, published September 22, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.34%, the 27th percentile. Fixed in mcp-atlassian 0.22.0.
References
github.com/sooperset/mcp-atlassian/security/advisories/GHSA-v9m3-wfh8-5646
github.com/sooperset/mcp-atlassian/pull/1448
github.com/sooperset/mcp-atlassian/commit/b041733473f95119dd539542a43c280737a8e460
github.com/sooperset/mcp-atlassian/releases/tag/v0.22.0
github.com/advisories/GHSA-v9m3-wfh8-5646
github.com/CVEProject/cvelistV5/tree/main/cves/2026/77xxx/CVE-2026-77249.json
nvd.nist.gov/vuln/detail/CVE-2026-77249
github.com/sooperset/mcp-atlassian
pypi.org/project/mcp-atlassian
Left out here: 29 versions and the rest of 3 source descriptions. The JSON record has them.