VNX-324: Use of a Key Past its Expiration Date
Reports code that accepts an expired certificate or signed token: swallowed CertificateExpiredException/ExpiredJwtException, jsonwebtoken ignoreExpiration: true, PyJWT verify_exp: False, ruby-jwt verify_expiration: false, OpenSSL verify callbacks that accept X509_V_ERR_CERT_HAS_EXPIRED, and X509_V_FLAG_NO_CHECK_TIME.
| Field | Value |
|---|---|
| Rule ID | VNX-324 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Java, Kotlin, JavaScript / TypeScript, Python, Ruby, C, C++ |
| CWE | CWE-324 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:M/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C |
| Tags | key-past-expiry cwe-324 jwt certificate |
| Source | internal/sast/rules/vnx-324.rego |
Overview
VNX-324 maps to CWE-324: Use of a Key Past its Expiration Date. It reports code that keeps accepting a certificate or a signed token after the expiry date its issuer gave it.
Why This Matters
Expiry bounds how long a leaked key, certificate or token stays useful. Code that ignores it turns a stolen credential into a permanent one, and keeps trusting certificates that were retired precisely because they could no longer be trusted.
What Gets Flagged
// FLAGGED: the expired certificate is swallowed and the handshake continues
} catch (CertificateExpiredException e) {
// old partner certificates are still in use
}
// FLAGGED: the claims of an expired token are used anyway
} catch (ExpiredJwtException e) {
return e.getClaims();
}
// FLAGGED
jwt.verify(token, key, { algorithms: ['RS256'], ignoreExpiration: true });
# FLAGGED
jwt.decode(token, key, algorithms=["HS256"], options={"verify_exp": False})
# FLAGGED
JWT.decode(token, secret, true, { algorithm: 'HS256', verify_expiration: false })
/* FLAGGED: the verify callback accepts an expired certificate */
if (err == X509_V_ERR_CERT_HAS_EXPIRED) {
return 1;
}
What Is Not Flagged
- A catch block that rethrows, returns
false/null, or answers 401/403 (readinge.getClaims()only to log it is fine). ignoreExpiration: false,verify_exp: True, and the names in comments.- Test files, where decoding an expired fixture is normal.
- Go, which VNX-GO-032 covers.
- Long certificate validity periods, which are a policy choice.
Remediation
- Keep expiry checks on. Let
checkValidity()and the JWT library reject expired material. - For refresh flows, verify a separate refresh token instead of accepting the expired access token’s claims.
- Rotate expired certificates rather than teaching the client to accept them.
References
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-324
// nosec vnx-324
Or record an ignore rule: vulnetix ignore add --rule vnx-324 --reason "...". See Suppressing findings.