T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/meeting_load.py:144
- Finding
- Unvalidated ICS Recurrence Interval Causes Infinite-Loop Denial of Service<![CDATA[ ## Vulnerability Details **File Location**: `scripts/meeting_load.py`, lines 144–173 **Vulnerability Type**: Improper input validation leading to denial of service **Risk Level**: Medium ### Vulnerable Code ```python interval = int(rule.get("INTERVAL", "1") or 1) count = int(rule["COUNT"]) if "COUNT" in rule else None until = parse_dt(rule["UNTIL"]) if "UNTIL" in rule else None byday = [WEEKDAY_MAP[d.strip()[-2:]] for d in rule["BYDAY"].split(",")] if "BYDAY" in rule else None if freq in ("DAILY",): cur, i = start, 0 while (until is None or cur <= until) and (count is None or i < count) and cur <= window_end: add(cur) cur += dt.timedelta(days=interval) i += 1 elif freq in ("WEEKLY", "MONTHLY", "YEARLY"): step_weeks = interval if freq == "WEEKLY" else interval * (4 if freq == "MONTHLY" else 52) # anchor: first week/day of the pattern anchor = start i = 0 while anchor <= window_end and (count is None or i < count) and (until is None or anchor <= until): if freq == "WEEKLY" and byday: week_start = dt.datetime.combine( anchor.date() - dt.timedelta(days=anchor.weekday()), dt.time(0)) for wd in sorted(byday): occ = week_start + dt.timedelta(days=wd, hours=anchor.hour, minutes=anchor.minute) if occ >= anchor or anchor.weekday() == wd: if count is None or i < count: add(occ) i += 1 else: add(anchor) i += 1 anchor += dt.timedelta(weeks=step_weeks) ``` ### Technical Analysis The ICS `RRULE` parser converts the attacker-controlled `INTERVAL` value to an integer but does not verify that it is positive. Recurrence expansion relies on this interval to advance `cur` or `anchor`. For a daily recurrence with `INTERVAL=0`, this statement never changes the loop variable: ```pytho ...[truncated 2358 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Validate recurrence intervals before expansion and reject values below one: ```python try: interval = int(rule.get("INTERVAL", "1") or 1) except ValueError as exc: raise ValueError("RRULE INTERVAL must be an integer") from exc if interval < 1: raise ValueError("RRULE INTERVAL must be at least 1") ``` 2. Validate other numeric recurrence fields, including `COUNT`, and reject zero, negative, malformed, or unreasonably large values. 3. Add an independent expansion limit so parser safety does not depend exclusively on recurrence semantics: ```python MAX_OCCURRENCES = 10000 iterations = 0 while condition: iterations += 1 if iterations > MAX_OCCURRENCES: raise ValueError("recurrence expansion limit exceeded") # Expand the occurrence. ``` 4. Explicitly assert cursor progress on each loop iteration. Abort if the new recurrence cursor is not later than its prior value. 5. Catch validation errors at the command boundary and display a concise message identifying the malformed event or recurrence rule rather than exposing an unhandled traceback. 6. Add regression tests covering: - `INTERVAL=0` - Negative intervals - Non-integer intervals - Zero or negative `COUNT` - Extremely large recurrence values - Rules without `COUNT` or `UNTIL` - Enforcement of the maximum expansion limit ]]>
