GHSA-3gx8-q682-38mx
GHSA-3gx8-q682-38mx is a CWE-345 vulnerability in roadiz/openid. O3 Security confirms whether GHSA-3gx8-q682-38mx is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.
OpenID Connect nonce generated but never validated — ID token replay attack
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.
Blast Radius
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.18 |
| 🐘Packagist | roadiz/openid | ≥ 2.6.0&&< 2.6.31 | 2.6.31 |
| 🐘Packagist | roadiz/openid | ≥ 2.5.0&&< 2.5.45 | 2.5.45 |
| 🐘Packagist | roadiz/openid | all versions | 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. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.
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 pinpoints whether GHSA-3gx8-q682-38mx is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.
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 detects GHSA-3gx8-q682-38mx across Packagist dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.