T09 · Insecure Skill Coding Practices
- Location
geo_event_router.py:349- Finding
Cooldown Enforcement Bypass Through Inconsistent Timezone Handling
- Content
View full analysis
Vulnerability Details
File Location:
geo_event_router.py, lines 349-361
Vulnerability Type: Cooldown control bypass caused by inconsistent timezone handling and broad exception suppression
Risk Level: MediumVulnerable Code:
python if last_seen: try: last_time = datetime.fromisoformat(last_seen.replace('Z', '+08:00')) elapsed_minutes = (datetime.now() - last_time).total_seconds() / 60 if elapsed_minutes < cooldown: if score >= 70 and push_count > 0: return True, f"事件升级(冷却期内,评分{score})" return False, f"冷却期内({elapsed_minutes:.0f}/{cooldown} 分钟)" except: pass if push_count >= 3: return False, "已达到最大推送次数"Technical Analysis
The cooldown calculation mixes timezone-aware and timezone-naive datetime values. A
last_seenvalue containingZis transformed into a timestamp with a+08:00offset, causingdatetime.fromisoformat()to produce a timezone-aware object. By contrast,datetime.now()returns a timezone-naive object.Subtracting these objects raises a
TypeError. The unrestrictedexceptblock silently suppresses that error, after which execution proceeds without enforcing the 90-minute or 180-minute cooldown. ReplacingZ, which denotes UTC, with+08:00also changes the timestamp's meaning rather than correctly parsing it as UTC.Attack Path
- An attacker or upstream component capable of influencing persisted event state creates an entry under
state["event_cache"][event.event_id]. - The entry supplies an offset-bearing
last_seenvalue, such as2026-01-01T12:00:00Z, while keepingpush_countbelow three. should_push_event()replacesZwith+08:00and parses the value as a timezone-aware datetime.- The function attempts to subtract it from the timezone-naive result of
datetime.now(). - Python raises
TypeError, which the bar ...[truncated 933 chars]
- An attacker or upstream component capable of influencing persisted event state creates an entry under
- Remediation
View remediation
Remediation Suggestions
- Parse
Zas UTC (+00:00) rather than changing it to+08:00. - Normalize both timestamps to timezone-aware UTC values before subtraction.
- Use
datetime.now(timezone.utc)instead of the timezone-naivedatetime.now(). - Catch only expected parsing or type errors, such as
ValueErrorandTypeError. - Fail closed when cached timestamps are invalid: reject or defer the push rather than silently bypassing cooldown enforcement.
- Log malformed state with sufficient context for diagnosis, without exposing sensitive event data.
- Validate the event-cache schema when state is loaded, including timestamp format, severity, and numeric bounds for
push_count. - Add tests covering
Z, explicit offsets, naive timestamps, malformed timestamps, future timestamps, and daylight-saving transitions.
Example hardened implementation:
python from datetime import datetime, timezone if last_seen: try: normalized = last_seen[:-1] + "+00:00" if last_seen.endswith("Z") else last_seen last_time = datetime.fromisoformat(normalized) if last_time.tzinfo is None: raise ValueError("last_seen must include a timezone") last_time = last_time.astimezone(timezone.utc) elapsed_minutes = ( datetime.now(timezone.utc) - last_time ).total_seconds() / 60 if elapsed_minutes < cooldown: if score >= PUSH_THRESHOLD_HIGH and push_count > 0: return True, f"Event escalation during cooldown (score {score})" return False, ( f"Cooldown active ({elapsed_minutes:.0f}/{cooldown} minutes)" ) except (ValueError, TypeError) as exc: # Log the invalid cache entry and fail closed. return False, "Invalid cached event timestamp"- Parse
