Zion Boggan

In-depth vulnerability research, detection engineering & applied cryptography.

● Open to security-research & detection roles
GitHub · LinkedIn · Email
home / featured finding
Coordinated disclosure in progress

A certificate path-length limit that disappears
when you remove an unrelated field

A widely-deployed open-source cryptography library enforces an RFC 5280 path-length constraint (the rule that stops a subordinate CA from minting further CAs) only when the certificate also carries a separate, unrelated extension. Drop that extension and the limit is silently skipped: a CA that was explicitly forbidden from delegating can issue rogue sub-CAs that the library accepts as valid. I found it by variant-hunting a security patch the maintainers had just shipped. The fix closed one instance of the gating mistake and left this one behind.

Class · CWE-295 improper certificate validation Standard · RFC 5280 §6.1.4 / §4.2.1.9 Impact · CA constraint bypass Severity · Medium (~CVSS 6.0) Confirmed on the current shipped release
01

See the bug in your browser

This is a faithful, self-contained reproduction of the flaw's logic (no library named yet; that waits for the fix). You're looking at a certificate chain where a CA limited to pathLenConstraint = 0, meaning "you may issue end-entity certificates only, never another CA", has nonetheless issued a sub-CA. A correct validator must reject this. Toggle the keyUsage extension on that intermediate and watch the current library change its verdict on a chain that should always be rejected, while the patched build stays put.

minipki · verifyCertificateChain()

Certificate chain (attacker-supplied)

keyUsage extension on the constrained intermediate An unrelated field. Real CAs include it; minimal tooling often omits it.

Both validators re-evaluate the instant you flip the switch.

Same chain, two validators

Current library
With my one-line fix

One toggle, two verdicts. The current library lets the presence of an unrelated extension decide whether it enforces the path-length limit, so flipping keyUsage flips its answer on a chain that should always be rejected. The patched validator ignores that field and rejects the chain every time.

02

Why it happens

Certificate-chain validators decide whether each intermediate is allowed to act as a CA. RFC 5280 makes two of those decisions independent: §4.2.1.9 says a basicConstraints pathLenConstraint caps how many CAs may follow in the path, and §6.1.4 applies that cap to every intermediate unconditionally. The presence of a keyUsage extension is governed separately by §4.2.1.3 and has nothing to do with path-length processing.

The vulnerable code couples them anyway: the path-length check sits behind a guard that only runs if (keyUsage extension is present). The author's reasoning was that having parsed keyUsage they "know" the basic constraints are present too, but that conflates two orthogonal extensions. Remove keyUsage and a real, signed, constraint-bearing CA escapes its own limit. It's the same "gate a mandatory check on an optional field" anti-pattern that a recently-published advisory fixed for a sibling check. This is the instance that fix didn't reach.

Held until the fix ships: the exact library, file/line, the published advisory, and the real end-to-end proof-of-concept against the live release. Those will appear here once the maintainers release a patched version. Responsible disclosure first, write-up second. (Private report submitted to the maintainer.)
03

What I ruled out

Finding the bug was half the work; not crying wolf on the others was the rest. I ran four more independent deep analyses against the same library's most security-critical paths. Each produced a rigorous negative, and a negative I can defend is worth more than a finding I can't. This is the discipline that keeps a report from getting auto-rejected as noise.

RULED OUT

ASN.1 validator desync

A recently-rewritten schema validator does ignore trailing elements, but every trust-bearing sink is guarded by an outer length check or sits under a real signature. Not weaponizable.

RULED OUT

RSA PKCS#1 v1.5 forgery

Probed the Bleichenbacher / low-exponent class with real e=3 keys. Tight padding + full-byte parsing + exact-digest compare pin the hash to the low-order bytes. No no-private-key forgery.

RULED OUT

Ed25519 malleability

Differential-tested against OpenSSL across non-canonical, low-order and cofactor edge cases. The S<L fix plus byte-exact R compare make the accepted-signature set a singleton. No divergence.

RULED OUT

X.509 chain confusion

DN/issuer spoofing, trust-anchor confusion, critical-extension smuggling, algorithm downgrade. Trust anchoring is byte-exact; no false-accept beyond the path-length issue above.

04

Disclosure timeline