GHSA-cv84-9p8j-fj68: High severity pip/icalendar vulnerability

Published Aug 25, 2026
·
Updated

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.

Affected Software

1 affected componentFixes available
pip/icalendar>=7.1.0<7.1.3
7.1.3

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade pip/icalendar to a version that resolves this vulnerability.

    Fixed in 7.1.3
  2. Upgrade

    Upgrade icalendar to a version that resolves this vulnerability.

    Fixed in 7.1.x
  3. Compensating control

    Add an application-level limit on iCalendar nesting depth or number of components before performing equality/membership/dedup/round-trip comparisons (since `Component.from_ical` imposes no depth limit and DoS is triggered by comparisons over nested subcomponents).

Event History

Aug 25, 2026
Advisory Published
via GitHub·07:27 PM
Data Sourced
via GitHub·07:27 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Which application behaviors make this issue reachable?

Exposure occurs when an application compares parsed calendar components from attacker-supplied .ics data. Relevant operations include ==, !=, membership tests, set or dictionary membership, deduplication, and test assertions.

2

What does an attacker need to supply to cause the denial of service?

An attacker can use an arbitrarily nested calendar component structure in a sub-kilobyte .ics file. The expensive behavior is triggered when the resulting parsed component is compared with another component.

3

Is authentication or user interaction required for exploitation?

The supplied CVSS vector indicates network reachability with no required privileges and no user interaction. The affected application must nevertheless accept attacker-controlled calendar data and perform a component equality-related operation on it.

4

How can I identify likely impact in an application?

Look for code paths that parse untrusted .ics files and then compare Component objects, directly or indirectly through container membership or deduplication. Affected paths may take minutes or appear to hang when handling deeply nested component chains.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203