GHSA-3gx8-q682-38mx — roadiz/openid
GHSA-3gx8-q682-38mx is a CWE-345 vulnerability in roadiz/openid. A fix is available for roadiz/openid — see the affected versions and patch details below.
OpenID Connect nonce generated but never validated — ID token replay attack
Exploitation Status
No confirmed exploitation observed yet
- CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.
Exploitation and automatability from CISA’s SSVC triage for GHSA-3gx8-q682-38mx.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
Real-World Exposure
roadiz/openid🐘roadiz/openid🐘roadiz/openid🐘roadiz/openidReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Packagist packages — download data is not available via public APIs for these ecosystems.
Description
Summary
The roadiz/openid package generates an OIDC nonce in OAuth2LinkGenerator::generate() and includes it in the authorization request sent to the identity provider, but never stores it and never validates it on the callback. The OpenIdJwtConfigurationFactory validation chain does not include a nonce constraint, and OpenIdAuthenticator::authenticate() never checks the nonce claim in the returned ID token against a stored value.
Details
In src/OAuth2LinkGenerator.php, a nonce is created and sent to the IdP:
'nonce' => $this->tokenGenerator->generateToken(),
However, this value is neither stored in session, cache, nor any other persistent store.
In src/OpenIdJwtConfigurationFactory.php, the JWT validation constraints are:
LooseValidAt(expiry)PermittedFor(audience)IssuedBy(issuer)HostedDomain(optional)UserInfoEndpoint(optional)
No nonce constraint is present.
In src/Authentication/OpenIdAuthenticator.php, the authenticate() method validates the state CSRF token correctly (fixed in v2.7.10), but never retrieves a stored nonce or compares it against the nonce claim in the ID token.
PoC
- Obtain a valid ID token from a legitimate OIDC flow for a target user (e.g. via network interception, browser history leak, or referrer header exposure on a non-HTTPS redirect).
- Replay the ID token: Since the nonce in the token is never cross-checked against a client-stored value, the token passes all validation constraints as long as it has not expired.
- Result: An attacker can authenticate as the victim within the ID token's validity window.
Additionally, in an authorization code flow with multiple concurrent sessions, a malicious IdP or a compromised token endpoint could inject a token with a mismatched nonce, and the application would accept it silently.
Impact
- ID token replay attacks: Valid but intercepted tokens can be reused for authentication within their validity period.
- Token injection attacks: A malicious or compromised identity provider can inject tokens across sessions without detection.
- Affects any Roadiz application using the
roadiz/openidpackage with OpenID Connect SSO.
The OIDC Core 1.0 specification (Section 3.1.3.7) explicitly requires clients to verify the nonce claim if it was present in the authorization request.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐘Packagist | roadiz/openid | ≥ 2.7.0&&< 2.7.18 | 2.7.18composer require roadiz/openid:^2.7.18 |
| 🐘Packagist | roadiz/openid | ≥ 2.6.0&&< 2.6.31 | 2.6.31composer require roadiz/openid:^2.6.31 |
| 🐘Packagist | roadiz/openid | ≥ 2.5.0&&< 2.5.45 | 2.5.45composer require roadiz/openid:^2.5.45 |
| 🐘Packagist | roadiz/openid | all versions | 2.3.43composer require roadiz/openid:^2.3.43 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for roadiz/openid, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update roadiz/openid to 2.7.18 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-3gx8-q682-38mx is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like GHSA-3gx8-q682-38mx can be triaged on real exposure rather than presence alone.
Tailored to GHSA-3gx8-q682-38mx. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is GHSA-3gx8-q682-38mx in your dependencies?
O3 Security finds GHSA-3gx8-q682-38mx across Packagist dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.