What CVE-2026-1529 is
A high-severity vulnerability (CVSS 8.1) was disclosed in Keycloak affecting its organization invitation feature. The root cause: the code parsing invitation JWTs never verified the cryptographic signature.
The flaw lived in org.keycloak.organization.utils.Organizations.parseInvitationToken, which decoded the invitation token's JWT payload without checking its signature. With one legitimate invitation token in hand, an attacker could simply edit the organization ID (org_id) and target email (eml) fields in the payload and self-register into an organization they were never invited to.
Webhani regularly reviews authentication implementations for clients, and this class of bug isn't an exotic attack technique — it's a pattern that recurs in JWT-handling code. Here's the general lesson worth pulling out of it.
Why this pattern keeps showing up
By design, a JWT's payload is just Base64-encoded and readable by anyone who decodes it. That "readable" property and "guaranteed unmodified" are two completely different guarantees — you only get the second one once you've verified the signature.
import jwt
# Dangerous: decoding without signature verification
payload = jwt.decode(token, options={"verify_signature": False})
org_id = payload["org_id"] # trusting a value the attacker can freely rewriteThis code looks like it's "handling a JWT," but functionally it's identical to trusting whatever value comes out of a Base64 string, unconditionally. It's easy for code like this to slip into a quickly-built invitation flow, password reset, or email confirmation feature — anywhere a one-time token gets rolled by hand.
The correct implementation pattern
Always route through signature verification, and never touch a payload that failed it:
import jwt
from jwt.exceptions import InvalidSignatureError, ExpiredSignatureError
try:
payload = jwt.decode(
token,
key=PUBLIC_KEY,
algorithms=["RS256"], # pin the algorithm explicitly
options={"require": ["exp", "org_id", "eml"]},
)
except (InvalidSignatureError, ExpiredSignatureError):
raise PermissionError("Invalid invitation token")
org_id = payload["org_id"] # only trusted after signature verificationPinning the algorithms parameter explicitly matters too. Code that leaves the algorithm unspecified, or accepts alg: none, opens the door to a separate class of attack (algorithm confusion) that effectively disables signature verification altogether.
A checklist for invitation and token-based features
When Webhani reviews a client's authentication layer, here's what we check specifically for invitation links and one-time tokens:
- Is signature verification enforced on every code path? — audit every place a token gets decoded to confirm none of them skip straight to deserialization
- Is the algorithm pinned explicitly? — do the allowed algorithms at issuance match the allowed algorithms at verification?
- Are critical payload fields re-checked against server-side state? — values like organization ID or target email shouldn't just pass signature verification; re-confirm them against the server's own record after decoding
- Are tokens one-time and time-bound? — is there a mechanism (used-flag, short expiry) that invalidates a token after it's consumed once?
Why using a mature IdP doesn't make this someone else's problem
"Our auth layer runs on a proven OSS product like Keycloak, so we're covered" is exactly the assumption this case breaks. A vulnerability in the IdP product itself becomes your service's risk the moment you miss the patch window.
- Build a habit of periodically checking security advisories for whatever IdP product you depend on
- If you've layered custom logic on top of the invitation or registration flow, check whether your own assumptions still hold after the IdP patches its side
- For a CVSS 8.1-class vulnerability, don't wait for your normal patch cadence — keep a separate emergency-patch path ready to go
Takeaway
CVE-2026-1529 is a bug in one specific product, but it's also a textbook example of a pitfall common to any JWT-handling code. "Decodable" and "verified" are not the same thing — a basic principle, but one that's easy to drop precisely when a team rushes through a "minor" feature like an invitation flow or one-time link. Webhani continues to check that this fundamental discipline holds whenever we review a client's authentication implementation.
Sources: CVE-2026-1529 (Red Hat Customer Portal), CVE-2026-1529 Forged invitation JWT enables cross-organization self-registration (GitHub keycloak/keycloak)