Back to skill

Security audit

Geo Event Router

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent Chinese-language event scoring and notification-routing helper with a limited cooldown bug but no evidence of hidden access, exfiltration, persistence, or destructive behavior.

Review this as a Chinese-language utility. Before installing, confirm that Chinese-only output is acceptable and be aware that the optional LLM analyzer may receive truncated news content if that dependency is installed. The cooldown logic should be fixed before relying on it for strict anti-spam or alert-fatigue controls.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
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: Medium

Vulnerable 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_seen value containing Z is transformed into a timestamp with a +08:00 offset, causing datetime.fromisoformat() to produce a timezone-aware object. By contrast, datetime.now() returns a timezone-naive object.

Subtracting these objects raises a TypeError. The unrestricted except block silently suppresses that error, after which execution proceeds without enforcing the 90-minute or 180-minute cooldown. Replacing Z, which denotes UTC, with +08:00 also changes the timestamp's meaning rather than correctly parsing it as UTC.

Attack Path

  1. An attacker or upstream component capable of influencing persisted event state creates an entry under state["event_cache"][event.event_id].
  2. The entry supplies an offset-bearing last_seen value, such as 2026-01-01T12:00:00Z, while keeping push_count below three.
  3. should_push_event() replaces Z with +08:00 and parses the value as a timezone-aware datetime.
  4. The function attempts to subtract it from the timezone-naive result of datetime.now().
  5. Python raises TypeError, which the bar ...[truncated 933 chars]
Remediation
View remediation

Remediation Suggestions

  • Parse Z as 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-naive datetime.now().
  • Catch only expected parsing or type errors, such as ValueError and TypeError.
  • 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"
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (3)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The natural-language content of the skill forces a specific language for users and operators, which can violate language/locale policy when no opt-in or alternative is provided. The file does not state that the skill is intentionally limited to a Chinese-speaking or region-specific context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This Python file contains natural-language documentation entirely in Chinese, and multiple user-facing decision messages later in the file are also hard-coded in Chinese. Under the policy, forcing a specific language without user opt-in or a documented regional justification is a locale-policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The push-decision function returns operational messages such as '事件升级', '冷却期内', and '高优先级' only in Chinese. Because these are runtime-facing messages and the file provides no language selection or documented locale constraint, they violate the language/locale policy.

Content

No source excerpt is available for this finding.