Describe the bug
While reviewing the new (2.5) OAuth/OpenID Connect support I noticed three token-validation gaps. These are hardening / spec-compliance issues (2.5 is unreleased, so filing here per SECURITY.md rather than as an advisory); their real-world impact depends on the configured Identity Provider (IdP), so I'm raising them for discussion rather than asserting a concrete bypass.
1. nonce not enforced when the id_token omits the claim — cups/oauth.c
// cups/oauth.c:1358-1364 (cupsOAuthGetTokens)
jwt = cupsJWTImportString(id_value, CUPS_JWS_FORMAT_COMPACT);
jnonce = cupsJWTGetClaimString(jwt, "nonce");
nonce = oauth_load_value(auth_uri, resource_uri, _CUPS_OTYPE_NONCE, false);
// Check nonce
if (!jwt || (jnonce && nonce && strcmp(jnonce, nonce)))
goto done;
When CUPS sent a nonce (it is persisted whenever the openid scope is requested), OIDC Core §3.1.3.7 requires the returned id_token to contain a matching nonce. Here, if the id_token omits the claim (jnonce == NULL), the jnonce && nonce && ... test short-circuits and the nonce check is skipped, so the token is accepted on signature alone. Suggested fix: if a nonce was sent (stored value exists), require jnonce != NULL && !strcmp(jnonce, nonce).
2. at_hash only validated for SHA-256-class id_tokens — cups/oauth.c:1377-1391
The access-token hash is always computed with sha2-256 and the code requires exactly 16 decoded at_hash bytes. For an id_token signed with an RS/ES/PS-384 or -512 algorithm the correct at_hash is 24/32 bytes, so a legitimate token is rejected (at_hash_bytes != 16 → goto done). The hash algorithm should follow the id_token's signing algorithm.
3. cupsd does not cryptographically validate inbound Bearer tokens; authorization uses the unverified email claim — scheduler/auth.c
In the Bearer branch (scheduler/auth.c:725-782), cupsd passes the token to cupsOAuthGetUserId(), which (when no cached identity exists) forwards it to the IdP userinfo_endpoint and trusts the JSON response (cups/oauth.c:1454-1518). On this inbound path there is no local verification of the token signature, iss, aud/azp, exp, or nbf (the existing cupsJWTHasValidSignature() / JWKS code is only used in the client-side token-exchange flow). Consequently a token minted by the same IdP for a different relying party can authenticate to CUPS (audience confusion), since CUPS never checks the token was issued for it.
Additionally, authorization matches the unverified email claim:
// scheduler/auth.c:1893
else if (!_cups_strcasecmp(username, name) || (con->email[0] && !_cups_strcasecmp(con->email, name)))
// scheduler/auth.c:1887,1920 -> cupsArrayFind(og->members, con->email)
email_verified is never consulted. If the configured IdP issues tokens with a user-settable/unverified email, a user could set email to a value listed in a policy's Require user ... or an OAuthGroup member file and gain that identity's access.
Suggested fixes: validate inbound tokens (signature via the IdP JWKS, plus iss/aud/exp) before trusting them, and require email_verified before using email for authorization decisions.
Expected behavior
Token and claim validation should follow the OIDC spec (enforce nonce when sent, algorithm-appropriate at_hash, and audience/expiry/email_verified checks).
System Information:
- OS and its version: Ubuntu 24.04 (x86_64)
- CUPS version: master / 2.5b1 (OAuth/OIDC support is 2.5-only)
Additional context
These are validation/hardening gaps rather than a demonstrated exploit; severity is IdP-dependent. Happy to split into separate issues if the maintainers prefer.
Describe the bug
While reviewing the new (2.5) OAuth/OpenID Connect support I noticed three token-validation gaps. These are hardening / spec-compliance issues (2.5 is unreleased, so filing here per
SECURITY.mdrather than as an advisory); their real-world impact depends on the configured Identity Provider (IdP), so I'm raising them for discussion rather than asserting a concrete bypass.1.
noncenot enforced when theid_tokenomits the claim —cups/oauth.cWhen CUPS sent a
nonce(it is persisted whenever theopenidscope is requested), OIDC Core §3.1.3.7 requires the returnedid_tokento contain a matchingnonce. Here, if theid_tokenomits the claim (jnonce == NULL), thejnonce && nonce && ...test short-circuits and the nonce check is skipped, so the token is accepted on signature alone. Suggested fix: if anoncewas sent (stored value exists), requirejnonce != NULL && !strcmp(jnonce, nonce).2.
at_hashonly validated for SHA-256-class id_tokens —cups/oauth.c:1377-1391The access-token hash is always computed with
sha2-256and the code requires exactly 16 decodedat_hashbytes. For anid_tokensigned with an RS/ES/PS-384 or -512 algorithm the correctat_hashis 24/32 bytes, so a legitimate token is rejected (at_hash_bytes != 16→goto done). The hash algorithm should follow theid_token's signing algorithm.3. cupsd does not cryptographically validate inbound Bearer tokens; authorization uses the unverified
emailclaim —scheduler/auth.cIn the Bearer branch (
scheduler/auth.c:725-782), cupsd passes the token tocupsOAuthGetUserId(), which (when no cached identity exists) forwards it to the IdPuserinfo_endpointand trusts the JSON response (cups/oauth.c:1454-1518). On this inbound path there is no local verification of the token signature,iss,aud/azp,exp, ornbf(the existingcupsJWTHasValidSignature()/ JWKS code is only used in the client-side token-exchange flow). Consequently a token minted by the same IdP for a different relying party can authenticate to CUPS (audience confusion), since CUPS never checks the token was issued for it.Additionally, authorization matches the unverified
emailclaim:email_verifiedis never consulted. If the configured IdP issues tokens with a user-settable/unverifiedemail, a user could setemailto a value listed in a policy'sRequire user ...or an OAuthGroup member file and gain that identity's access.Suggested fixes: validate inbound tokens (signature via the IdP JWKS, plus
iss/aud/exp) before trusting them, and requireemail_verifiedbefore usingemailfor authorization decisions.Expected behavior
Token and claim validation should follow the OIDC spec (enforce
noncewhen sent, algorithm-appropriateat_hash, and audience/expiry/email_verifiedchecks).System Information:
Additional context
These are validation/hardening gaps rather than a demonstrated exploit; severity is IdP-dependent. Happy to split into separate issues if the maintainers prefer.