From: CPANSec Security Scanner Bot Subject: [PATCH] OIDC::Lite: pin the ID Token signature algorithm in verify() OIDC::Lite::Model::IDToken::verify() derived the accepted-algorithm allowlist it hands to JSON::WebToken from the token's own `alg` header whenever the caller had not pinned an algorithm. Because that allowlist is the only thing pinning the algorithm, sourcing it from the untrusted token defeats the defense entirely: an attacker forges an unsigned alg=none ID Token, or an HS256 token signed with the verifier's RSA public key (RS->HS confusion), and verify() accepts it -- forging the OpenID Connect authentication assertion (impersonate any user at the Relying Party). This patch makes verify() fail closed: it refuses to verify unless the caller pinned an algorithm, and never accepts "none" (an OIDC ID Token must carry a real signature). This matches RFC 8725 (JWT BCP) section 3.1 "Use Algorithm-Specific Validation" and the same fix shape adopted across the JWT ecosystem. Callers must use the documented load($token, $key, $alg) form (or set alg via new()). Related (not changed here): get_token_string() likewise defaults the *minting* side to alg=none when the issuer omits alg (lib/OIDC/Lite/Model/IDToken.pm); issuers should default to a real signing algorithm. --- a/lib/OIDC/Lite/Model/IDToken.pm +++ b/lib/OIDC/Lite/Model/IDToken.pm @@ -200,13 +200,18 @@ $self->key('') unless($self->key); - unless ($self->alg) { - if ($self->header->{alg}) { - $self->alg($self->header->{alg}); - } else { - $self->alg('none'); - } - } + # SECURITY: the accepted signature algorithm MUST be pinned by the + # caller and MUST NOT be taken from the (attacker-controlled) token + # header. Sourcing the accepted-algorithm allowlist from the token + # enables alg=none forgery and RS->HS key confusion (forge by signing + # HS256 with the verifier's RSA public key). Refuse to verify a token + # whose algorithm was not pinned by the caller, and never accept + # "none" (an OpenID Connect ID Token must carry a real signature). + # See RFC 8725 (JWT BCP) section 3.1 "Use Algorithm-Specific Validation". + return 0 + unless($self->alg); + return 0 + if($self->alg eq 'none'); my $payload = undef; eval{