Hi,
I found a reachable stack-overflow DoS in simple_asn1 and would like to flag it for your evaluation.
Summary
from_der_ (src/lib.rs:341-383) decodes a sequence of TLVs. When it meets a constructed tag whose class is not Universal (i.e. Application, Context-Specific, or Private), it speculatively recurses into the body to decode it as an "explicit-tagged" wrapper:
// src/lib.rs:358-372
if class != ASN1Class::Universal {
if constructed {
// Try to read as explicitly tagged
if let Ok(mut items) = from_der_(body, start_offset + index) {
// ^^^^^^^^^ no depth parameter, no cap
if items.len() == 1 {
result.push(ASN1Block::Explicit(class, soff, tag, Box::new(items.remove(0))));
// ...
Each nested context-specific constructed tag adds one frame to from_der_. No depth counter, no iteration cap, no configurable limit. grep -n "max_depth\|MAX_DEPTH\|recursion" src/lib.rs returns zero hits.
A payload of the form A0 02 A0 02 A0 02 … A0 00 (nested [0] context-specific constructed tags) exhausts the thread stack, triggers SIGSEGV on the guard page, and aborts the process.
I verified this on simple_asn1 0.6.4 (current as of April 2026, the latest release on crates.io, published February 12, 2026).
Verified test results
PoC built against simple_asn1 = "0.6" (resolves to 0.6.4). Run on a 256 KiB thread stack (std::thread::Builder::stack_size(256 * 1024)) for reproducible thresholds.
| Depth |
Payload size |
Result |
| 100 |
239 B |
OK |
| 200 |
425 B |
OK |
| 300 |
837 B |
OK |
| 400 |
1,633 B |
stack-overflow abort (exit 134) |
| 500 |
1,833 B |
stack-overflow abort |
| 1000 |
3,833 B |
stack-overflow abort |
| 20000 |
83,407 B |
stack-overflow abort |
Minimum crash payload (hex)
Depth 400, 1,633 bytes. Structure is A0 82 XX XX wrapping A0 82 XX XX wrapping … A0 00 at the core. Generated by the PoC's build_nested_explicit(400) function.
Suggested fix
Add a depth counter to from_der_ and cap it.
Thanks for maintaining simple_asn1. Please let me know if anything else I should provide.
Hi,
I found a reachable stack-overflow DoS in
simple_asn1and would like to flag it for your evaluation.Summary
from_der_(src/lib.rs:341-383) decodes a sequence of TLVs. When it meets a constructed tag whose class is not Universal (i.e. Application, Context-Specific, or Private), it speculatively recurses into the body to decode it as an "explicit-tagged" wrapper:Each nested context-specific constructed tag adds one frame to
from_der_. No depth counter, no iteration cap, no configurable limit.grep -n "max_depth\|MAX_DEPTH\|recursion" src/lib.rsreturns zero hits.A payload of the form
A0 02 A0 02 A0 02 … A0 00(nested[0]context-specific constructed tags) exhausts the thread stack, triggers SIGSEGV on the guard page, and aborts the process.I verified this on simple_asn1 0.6.4 (current as of April 2026, the latest release on crates.io, published February 12, 2026).
Verified test results
PoC built against
simple_asn1 = "0.6"(resolves to 0.6.4). Run on a 256 KiB thread stack (std::thread::Builder::stack_size(256 * 1024)) for reproducible thresholds.Minimum crash payload (hex)
Depth 400, 1,633 bytes. Structure is
A0 82 XX XXwrappingA0 82 XX XXwrapping …A0 00at the core. Generated by the PoC'sbuild_nested_explicit(400)function.Suggested fix
Add a depth counter to
from_der_and cap it.Thanks for maintaining
simple_asn1. Please let me know if anything else I should provide.