CVE-2026-55099: icalendar: Algorithmic Complexity in Equality
Summary
Component.eq compares subcomponents in O(2^n) time relative to nesting depth. Because the parser accepts arbitrarily nested components, a sub-kilobyte .ics file is enough to make a single equality check run for minutes or hang indefinitely. Any application that compares parsed components (==, !=, in, set/dict membership, deduplication, test assertions) against attacker-supplied calendar data is exposed to denial of service.
Details
Component subclasses dict and stores children in a separate subcomponents list. eq (src/icalendar/cal/component.py:642-665) checks set-equivalence of children with two membership loops:
python def eq(self, other): if len(self.subcomponents) != len(other.subcomponents): return False if not super().eq(other): return False for subcomponent in self.subcomponents: if subcomponent not in other.subcomponents: return False for subcomponent in other.subcomponents: if subcomponent not in self.subcomponents: return False return True
Each ... not in ... test invokes eq on the children. For a nested chain, both loops descend the full subtree, so each level spawns two recursive comparisons: T(n) = 2·T(n-1) → O(2^n).
Parsing does not gate this. Component.fromical builds the structure iteratively and imposes no depth limit, so BEGIN:VEVENT blocks can be nested to any depth (parsing the payload below is instant). The cost is paid only when a comparison occurs, and only when the operands are equal far enough down to keep both loops recursing, a condition the attacker controls by submitting equal subtrees.
PoC
python from icalendar import Calendar
d = 26 event = b"BEGIN:VEVENT\r\n" d + b"END:VEVENT\r\n" d ics = b"BEGIN:VCALENDAR\r\n" + event + event + b"END:VCALENDAR\r\n"
cal = Calendar.fromical(ics) a, b = cal.subcomponents a == b
Measured on icalendar 7.1.x, CPython 3.14:
| Payload | Depth | == time | |---|---|---| | 552 B | 20 | 0.76 s | | 656 B | 24 | 12 s | | 708 B | 26 | 48 s | | ~800 B | 30 | ~13 min |
A single uploaded file supplies both operands (two identical nested events), so no second input is needed. The same blowup occurs in round-trip checks (cal == Calendar.fromical(cal.toical())) and in any membership/dedup logic over subcomponents.
Impact
Algorithmic-complexity denial of service (CWE-407). Unauthenticated; a few hundred bytes of input pin a CPU core indefinitely. It affects any service that parses untrusted iCalendar data and then compares components for equality or membership, including calendar sync/import endpoints, invite processing, dedup, and round-trip/normalization checks. It is not triggered by parsing alone, and a comparison against an early-differing object short-circuits harmlessly, so impact is limited to code paths that perform such comparisons.
Fix
Component.eq rewritten to walk an explicit stack instead of recursing, matching each pair of nested components exactly once. Equality is now linear in the number of components and preserves the existing multiset equivalence and commutativity semantics.
Other sources
icalendar is an RFC 5545 compatible parser and generator of iCalendar files for Python. From 7.1.0 until 7.1.3, the Component equality method in src/icalendar/cal/component.py compares nested subcomponents with two membership loops, and each membership test invokes the same method on child components, causing O(2^n) work relative to nesting depth. Component.fromical accepts arbitrarily nested BEGIN:VEVENT blocks without a depth limit, so an attacker can submit a sub-kilobyte .ics file containing equal nested subtrees and trigger the cost when an application performs equality, inequality, membership, deduplication, test-assertion, round-trip, or normalization comparisons. Parsing alone does not trigger the issue, and comparisons that differ early short-circuit, but a few hundred bytes can pin a CPU core for minutes or indefinitely, causing denial of service in calendar sync or import endpoints, invite processing, and other comparison paths. This issue is fixed in version 7.1.3.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/icalendarto a version that resolves this vulnerability.Fixed in 7.1.3 - Upgrade
Upgrade
icalendarto a version that resolves this vulnerability.Fixed in 7.1.3 - Compensating control
Ensure untrusted .ics/iCalendar data is not subjected to equality/inequality/membership/deduplication/normalization comparisons (e.g., avoid operations like Component.__eq__ such as `cal == Calendar.from_ical(cal.to_ical())`) on attacker-controlled, deeply nested BEGIN:VEVENT inputs until patched.