Feb 19, 2026·7 min read·6 visits
Cosign checked the validity of CA chains based on the leaf certificate's issuance time rather than the signature time. This allowed expired Intermediate CAs to validly sign artifacts, provided the leaf cert was created while the parent was still alive.
A temporal logic flaw in Sigstore Cosign's certificate validation allowed expired intermediate Certificate Authorities to validate signatures if the leaf certificate was issued before the parent's expiration. While low severity for the public Sigstore infrastructure due to ephemeral certificates, this flaw exposes private PKI deployments to 'Zombie Cert' attacks.
In the world of cryptography, time is usually a hard constraint. A certificate is valid from Point A to Point B. If you try to use it at Point C (where C > B), the math should scream at you. Simple, right? Well, sigstore/cosign—the darling of the secure supply chain world—decided to get a little creative with how it perceives the fourth dimension.
This vulnerability isn't your typical memory corruption or injection flaw. It's a logic bug in how X.509 certificate chains are verified. Specifically, it’s about reference times. When verifying a digital signature, you have to ask: "Was the certificate valid when this signature was made?" Cosign answered that question correctly for the leaf certificate (the one doing the signing), but it got a little confused about the parents.
Imagine verifying a driver's license. You check the expiration date on the license (the leaf). It's valid. But to trust the license, you also need to trust the DMV that issued it (the Intermediate CA). Cosign's bug is equivalent to accepting a license issued by a DMV branch that closed down three years ago, just because the branch was open on the day the license was printed. It’s a subtle distinction, but in the binary world of trust, subtle distinctions are where the exploits hide.
To understand this bug, we have to look at how X.509 validation usually works versus how it works in the context of artifact signing. In a standard TLS handshake (like HTTPS), we check if the chain is valid right now. In artifact signing, we check if the chain was valid at the time of signing. This requires passing a specific time into the verification logic.
The root cause of CVE-2026-24122 lies in a split-brain decision made during this process. When Cosign verified a signature, it effectively performed two checks with two different distinct timelines:
By pinning the chain validation to the NotBefore time of the leaf, Cosign ignored everything that happened to the Intermediate CA after the leaf was issued. If the Intermediate CA expired, was revoked, or simply timed out between the leaf issuance and the signature creation, Cosign wouldn't notice. It was validating the chain based on a historical snapshot, not the relevant moment of use. This created a "Zombie Window"—a period where a dead parent CA could still ostensibly support active child certificates.
The fix is technically simple but conceptually critical. We need to force the entire chain verification to respect the same clock: the time the signature was created (or the integratedTime from the transparency log).
Here is a simplified view of the logic change in Go's crypto/x509 usage within Cosign. The patch essentially stops using the leaf's creation time as the reference for the chain.
The Vulnerable Logic (Conceptual):
// OLD: Chain is verified against when the certificate started existing
verifyOptions := x509.VerifyOptions{
Roots: trustedRoots,
Intermediates: trustedIntermediates,
CurrentTime: leafCert.NotBefore, // <--- THE BUG
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning},
}The Fixed Logic (Patch 3c9a736):
// NEW: Chain is verified against the actual signature timestamp
verifyOptions := x509.VerifyOptions{
Roots: trustedRoots,
Intermediates: trustedIntermediates,
CurrentTime: signatureTimestamp, // <--- THE FIX
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning},
}The actual commit 3c9a7363f563db76d78e2de2cabd945450f3781e ensures that CurrentTime in the verification options is consistently set to the trusted timestamp of the signature. This closes the gap; if the Intermediate CA is expired at signatureTimestamp, the whole chain fails, regardless of when the leaf was born.
While the CVSS is low because this requires a specific PKI setup, the exploit scenario is fascinating. An attacker needs control over an Intermediate CA that is about to expire, or a compromised key from an expired Intermediate CA (assuming revocation checks are also bypassed or the CRL is unavailable).
The Attack Recipe:
Int-CA that expires at T=100.T=90, you use Int-CA to issue a malicious Leaf Certificate Evil-Leaf. Evil-Leaf is valid from T=90 to T=200.T=100, Int-CA expires. It is now dead. In a proper system, trust anchors derived from it should fail.T=150, you sign a malicious container image using Evil-Leaf. You attach a trusted timestamp for T=150.The Execution: The victim pulls the image. Cosign v2.x checks the signature:
Evil-Leaf valid at T=150? Yes (valid until T=200).Evil-Leaf.NotBefore (T=90). Was Int-CA valid at T=90? YES.Cosign validates the signature. You have successfully bypassed the expiration of the Intermediate CA, allowing a compromised or deprecated key to continue signing payloads indefinitely (or until the leaf finally dies).
You might be wondering: "If I can bypass CA expiration, why is this only a 3.7 (Low)?" The answer lies in the ecosystem design of Sigstore. The public instance of Sigstore (used by millions of open-source projects) issues Fulcio certificates that are valid for only 10 minutes. The Intermediate CAs are long-lived.
In the public infrastructure, it is mathematically impossible for the Intermediate CA to expire during the 10-minute validity window of a leaf cert unless the Root CA is rotating keys in a very bizarre way. The window of opportunity is practically zero.
However, the story changes for Private Deployments. If your company runs an internal Sigstore stack (which many do for proprietary software) and you manage your own PKI with traditional long-lived certificates (e.g., 1-year Leafs, 2-year Intermediates), you are vulnerable. If an Intermediate CA key is leaked after it expires, an attacker could use this logic flaw to sign malware that your internal build systems will trust blindly. It essentially breaks the concept of "Forward Secrecy" for expired CA keys.
The remediation is straightforward, but for those managing custom PKIs, it serves as a good reminder to audit your chain validation logic.
Immediate Action: Upgrade to Cosign v3.0.5. This version enforces strict time synchronization across the entire chain. If you are using Cosign as a library in your own Go tools, you need to go get -u and rebuild.
For the Paranoid: If you cannot upgrade immediately, you must perform out-of-band verification. This means extracting the certificate and signature from the artifact and using openssl or a similar tool to verify the chain against the current time (or the timestamp time).
> openssl verify -CAfile root.pem -untrusted intermediate.pem -attime <timestamp> leaf.pem
This manual check will fail correctly where Cosign previously succeeded.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
sigstore/cosign sigstore | < 3.0.5 | 3.0.5 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-295 |
| Attack Vector | Network |
| CVSS v3.1 | 3.7 (Low) |
| Complexity | High |
| Privileges Required | None |
| Exploit Status | Theoretical / PoC |
The software does not validate, or incorrectly validates, a certificate.