Back to skill

Security audit

Token Usage Monitor

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent token-usage tracker, but its local storage implementation is unsafe enough that users should review it before installing.

Install only if you are comfortable with persistent local usage logs. Before using it, fix or review the data-file handling so '~' is expanded to the intended home directory, storage is restricted to a dedicated directory, symlink writes are avoided, and the usage log has appropriate permissions and retention expectations.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/token_usage_tracker.py:13
Finding
Unsafe Local Data-File Path Handling Enables Symlink-Directed File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `scripts/token_usage_tracker.py`, lines 13-37 **Vulnerability Type**: Unsafe path handling, symlink following, and insecure file permissions **Risk Level**: Medium ### Vulnerable Code ```python class TokenUsageTracker: def __init__(self, data_file: str = "~/.openclaw/token_usage.json"): self.data_file = data_file self.usage_data = self._load_data() def _load_data(self) -> Dict: """Load token usage data from file""" try: with open(self.data_file, 'r') as f: return json.load(f) except FileNotFoundError: return { "sessions": {}, "daily_totals": {}, "thresholds": {}, "model_pricing": { "gpt-4": 0.03 / 1000, "gpt-3.5-turbo": 0.0015 / 1000, "claude-2": 0.0110 / 1000, "doubao-seed": 0.002 / 1000 } } def _save_data(self): """Save token usage data to file""" import os os.makedirs(os.path.dirname(self.data_file), exist_ok=True) with open(self.data_file, 'w') as f: json.dump(self.usage_data, f, indent=2) ``` ### Technical Analysis The default data path contains `~`, but Python's `open()` and `os.makedirs()` functions do not automatically expand this notation. Consequently, the default path is interpreted relative to the current working directory as `./~/.openclaw/token_usage.json`, rather than as a file beneath the executing user's home directory. The save operation also opens the destination with mode `w` without checking whether the destination is a symbolic link. If an attacker can prepare the relative path in the process's working directory, the attacker can place a symbolic link at the expected destination. The subsequent save will follow that link and truncate or replace any linked file that i ...[truncated 1737 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Expand and normalize the configured path before any file operation: ```python self.data_file = os.path.abspath(os.path.expanduser(data_file)) ``` 2. Ensure the resolved path remains beneath an explicitly approved storage directory. 3. Create the storage directory with mode `0o700`. 4. Reject symbolic links for both the destination and relevant parent directories. 5. Create files with mode `0o600` using `os.open()` and appropriate flags, including `O_NOFOLLOW` where supported. 6. Save through a securely created temporary file in the same directory, call `flush()` and `os.fsync()`, and atomically replace the destination with `os.replace()`. 7. Document the resolved storage location and avoid running the tracker from attacker-writable working directories. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/token_usage_tracker.py:40
Finding
Negative Token Counts Permit Usage Accounting and Threshold-Alert Bypass<![CDATA[ ## Vulnerability Details **File Location**: `scripts/token_usage_tracker.py`, lines 40-67 and 163-182 **Vulnerability Type**: Missing numeric input validation **Risk Level**: Low ### Vulnerable Code ```python def track_usage(self, session_id: str, model: str, prompt_tokens: int, completion_tokens: int): """Track token usage for a session""" timestamp = datetime.datetime.now().isoformat() total_tokens = prompt_tokens + completion_tokens # Update session data if session_id not in self.usage_data["sessions"]: self.usage_data["sessions"][session_id] = [] self.usage_data["sessions"][session_id].append({ "timestamp": timestamp, "model": model, "prompt_tokens": prompt_tokens, "completion_tokens": completion_tokens, "total_tokens": total_tokens }) # Update daily totals date_str = datetime.datetime.now().strftime("%Y-%m-%d") if date_str not in self.usage_data["daily_totals"]: self.usage_data["daily_totals"][date_str] = {} if model not in self.usage_data["daily_totals"][date_str]: self.usage_data["daily_totals"][date_str][model] = { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 } self.usage_data["daily_totals"][date_str][model]["prompt_tokens"] += prompt_tokens self.usage_data["daily_totals"][date_str][model]["completion_tokens"] += completion_tokens self.usage_data["daily_totals"][date_str][model]["total_tokens"] += total_tokens ``` The corresponding command-line parsing and validation are: ```python parser.add_argument("--prompt-tokens", type=int, help="Prompt tokens used (required for --track)") parser.add_argument("--completion-tokens", type=int, help="Completion tokens used (required for --track)") ``` ```python if args.track: if not all([args.model, args.prompt_tokens, args.completion_tokens]): parser.error("--track requires --mod ...[truncated 2378 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate token counts at the API boundary and reject booleans, negative values, and unreasonable values: ```python def _validate_token_count(name: str, value: int) -> None: if isinstance(value, bool) or not isinstance(value, int): raise TypeError(f"{name} must be an integer") if value < 0: raise ValueError(f"{name} must be non-negative") ``` 2. Invoke validation inside `track_usage()` so that every caller is protected, rather than relying only on command-line validation. 3. Replace truthiness-based required-argument checks with explicit `None` checks: ```python if args.model is None or args.prompt_tokens is None or args.completion_tokens is None: parser.error("--track requires --model, --prompt-tokens, and --completion-tokens") ``` 4. Validate loaded JSON records before using them in totals or cost calculations. 5. Consider setting an upper bound based on expected provider limits to reduce accidental corruption. 6. If accounting integrity is important, record immutable usage events and derive totals from validated events rather than directly mutating aggregate counters. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Lp3

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding
The skill advertises or implies code that reads and writes local files, but it does not declare any tool scope such as permissions or allowed-tools. This creates an authorization ambiguity where an agent may execute file-capable resources without explicit user-visible constraints, increasing the risk of unintended filesystem access or persistence.

Session Persistence

Medium
Category
Rogue Agent
Content
### scripts/

Create only the resource directories this skill actually needs. Delete this section if no resources are required.

### scripts/
- `token_usage_tracker.py`: Main script for tracking and reporting token usage
Confidence
76% confidence
Finding
The skill explicitly describes persistent storage of usage data in ~/.openclaw/token_usage.json, which introduces session persistence on the local machine. Even though the stated purpose is benign, persistent files can accumulate potentially sensitive metadata about model usage patterns and may be read, modified, or retained longer than intended.

Session Persistence

Medium
Category
Rogue Agent
Content
### Permission Issues

If you encounter permission errors when writing to the data file, ensure the OpenClaw user has write access to the `~/.openclaw/` directory:

```bash
chown -R $USER:$USER ~/.openclaw/
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Missing User Warnings

Low
Confidence
89% confidence
Finding
This markdown file advertises alert channels including email and webhook, which can send token-usage or model-usage information off-system. The README does not include any user warning about possible data transmission, privacy considerations, or the need to review what telemetry is included in alerts.

Missing User Warnings

Low
Confidence
83% confidence
Finding
The README instructs users to integrate automatic tracking by extracting token metadata and recording it with a session identifier. For a markdown file, this affects user data/privacy behavior, but the description does not warn that usage telemetry tied to sessions may be retained or analyzed.

Static analysis

No suspicious patterns detected.