Security Advisories (2)
CVE-2026-75628 (2026-08-20)

Punk::OAuth2 versions before 0.03 for Perl allow an attacker-chosen off-site redirect after login because same_origin_path accepts a backslash or tab in the return parameter. oauth2_login reads the return parameter from the initiation request, runs same_origin_path over it, and stores the survivor in the session flow record as the post-login redirect target. That check rejects a value that does not begin with a slash, one with a slash as its second byte, and one containing CR or LF. A backslash and a tab pass. The URL Standard treats a backslash as equivalent to a slash for special schemes, so `/\evil.example` parses with the authority `evil.example`. It also strips ASCII tab before parsing, so a tab between two leading slashes leaves `//evil.example`. A crafted link to the application's own login route lands the victim on the attacker's site after a genuine authentication. The redirect carries no authorization code or access token.

CVE-2026-75866 (2026-08-22)

Punk::OAuth2::Server versions through 0.03 for Perl issue access tokens outside a client's registered scopes and grant types because no authorization path reads them. Punk::OAuth2::Server::Store registers scopes and grant_types per client and documents both as client registration. token dispatches on the grant_type in the request body, so a client registered for authorization_code alone can ask for client_credentials, and that arm passes the requested scope straight to the minter, which signs it into the at+jwt access token. authorize copies the query scope into the authorization code record without comparing it against the registration, leaving the optional consent hook as the only check between an arbitrary scope and the issued code. redirect_uris on the same client row is read and enforced. A registered client can obtain a correctly signed token carrying any scope it names, and a resource server running Punk::OAuth2::Checker accepts that token and honours the scope. A client registered without a secret authenticates on its client_id alone, so anyone who knows that identifier can request one.

Changes for version 0.01 - 2026-08-15

  • First version.
  • the client side of OAuth2 and OpenID Connect for Punk: authorization-code flow with PKCE (S256), signed single-use state, OIDC nonce, id_token verification through Crypt::JWS and a cached JWKS, normalized identities
  • oauth2 and oauth2_login keywords (both plugin/keyword orderings valid, to_app tripwire); presets google, github, generic oidc with RFC 8414/OIDC discovery (issuer-checked, SSRF-guarded)
  • context helpers oauth2_authurl, oauth2_refresh, oauth2_provider
  • implemented in XS over the house C ABIs (jws_abi, frj_abi, fetch_abi), with an xs/ directory of fragments like Punk: the Provider and JWKS objects, Tokens, presets, the whole login flow (state/nonce/PKCE mint, session flow records, the callback's state/iss/code validation, token exchange, identity normalization), id_token verification, form/URL/base_url/ safe_url/await all run in C; the only Perl is the plugin's Punk registration wiring (install_kw/route/helper) and POD-only module loaders
  • identity-only session default: provider tokens are handed to on_login and discarded (nothing token-shaped in the 4KB signed-cookie session)
  • authorization server (oauth2_server keyword): /authorize, /token, /revoke, /introspect, /jwks.json and RFC 8414 metadata; grants authorization_code + PKCE (S256), refresh with rotation and family revocation on reuse, and client_credentials; ES256 JWT access tokens (RFC 9068 at+jwt) the resource-server checker validates statelessly; client auth (basic or body, constant-time on digests); authenticate and consent hooks; a pluggable DBI store (SQLite, digest-only, auto_migrate) - all protocol logic in XS
  • resource-server checkers (Punk::OAuth2::Checker): jwt (local JWT validation via JWKS or a static key - allowlist, signature, iss/aud/exp/nbf, scope) and introspect (RFC 7662, cached by token SHA-256), matching the OpenAPI security-map contract, plus a guard wrapper emitting RFC 6750 WWW-Authenticate (401 invalid_token / 403 insufficient_scope); all validation in XS

Modules

OAuth2 and OpenID Connect for Punk applications
resource server bearer token checkers
a cached JWKS key set
provider presets for Punk::OAuth2
one configured OAuth2/OIDC provider
an OAuth2/OIDC authorization server
DBI storage for the authorization server
a token-endpoint response
shared helpers for Punk::OAuth2
social login for Punk applications