Back to skill

Security audit

Token Stats

Security checks for vulnerabilities and agentic risk

Overview

This skill is a token-usage reporter, but it reads local OpenClaw session history and has loose activation and path scoping that should be reviewed before installation.

Install only if you are comfortable with a skill reading local OpenClaw session-history files to summarize token usage. Review or fix the --agent path handling before use in shared or prompt-injection-prone environments, and invoke it only for explicit OpenClaw token-statistics requests.

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
scripts/token_stats.py:32
Finding
Path Traversal Through Unvalidated Agent Identifier## Vulnerability Details **File Location**: `scripts/token_stats.py`, lines 32 and 43-56 **Vulnerability Type**: Path traversal caused by unsafe path construction **Risk Level**: Medium ### Vulnerable Code ```python p.add_argument("--agent", default="main", help="Agent ID (default: main)") ``` ```python def find_session_files(agent_id, include_deleted): base = os.path.expanduser("~/.openclaw/agents/%s/sessions/" % agent_id) patterns = [base + "*.jsonl"] if include_deleted: patterns.append(base + "*.jsonl.deleted*") patterns.append(base + "*.jsonl.bak*") files = [] for pat in patterns: files.extend(glob.glob(pat)) return sorted(set(files), key=os.path.getmtime, reverse=True) def load_labels(agent_id): """Load session labels from sessions.json.""" sj_path = os.path.expanduser( "~/.openclaw/agents/%s/sessions/sessions.json" % agent_id ) ``` ### Technical Analysis The `--agent` command-line argument is accepted without validation and interpolated directly into filesystem paths. The application does not reject path separators or `..` components, nor does it canonicalize the resulting path and verify that it remains under the intended `~/.openclaw/agents/` directory. Consequently, an attacker who can influence the command-line arguments can supply a traversal value that causes both `find_session_files()` and `load_labels()` to access an unintended, locally accessible directory whose final component is `sessions`. Exploitation is constrained by the script's fixed filename patterns and parsers: the target directory must contain matching `*.jsonl` files or a `sessions.json` file, and meaningful output requires compatible JSON structures. The script does not print complete message contents, but it can expose derived token statistics, timestamps, session identifiers, and labels from files outside the intended agent directory. ### Attack Pa ...[truncated 1418 chars]
Remediation
## Remediation Suggestions 1. Restrict agent identifiers to a conservative allowlist, such as letters, digits, underscores, and hyphens: ```python import re AGENT_ID_PATTERN = re.compile(r"^[A-Za-z0-9_-]+$") def validate_agent_id(agent_id): if not AGENT_ID_PATTERN.fullmatch(agent_id): raise ValueError("Invalid agent ID") return agent_id ``` 2. Build paths with `pathlib.Path` rather than string interpolation. 3. Resolve both the trusted agents root and candidate directory, then enforce containment before performing any read: ```python from pathlib import Path def get_sessions_dir(agent_id): validate_agent_id(agent_id) agents_root = (Path.home() / ".openclaw" / "agents").resolve() sessions_dir = (agents_root / agent_id / "sessions").resolve() if agents_root not in sessions_dir.parents: raise ValueError("Agent path escapes the agents directory") return sessions_dir ``` 4. Use the validated directory returned by a single shared helper in both `find_session_files()` and `load_labels()` so that security checks cannot diverge. 5. Reject symbolic-link-based escapes by performing containment validation after path resolution. If the environment permits untrusted users to modify directories concurrently, open files using descriptor-relative APIs and appropriate no-follow protections to reduce time-of-check/time-of-use risks. 6. Add automated tests covering absolute paths, `../` traversal, nested traversal, path separators, symbolic links, valid agent identifiers, and directories that merely share the expected filename structure.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill instructs the agent to scan session JSONL files under the user's home directory, which is a file-read capability, but the manifest does not declare any tool scope or allowed-tools restriction. This creates an authorization and transparency gap: an agent may read potentially sensitive conversation logs without explicit permission boundaries, increasing the chance of unintended data exposure.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The skill description is broad enough to match common questions about usage or cost, which can cause the agent to invoke a file-scanning skill in situations where the user did not clearly request filesystem-backed analysis. Because the skill operates on historical session logs, overbroad activation can unnecessarily expose private usage metadata and conversation-derived information.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The example trigger '看看用量' is too vague and could match many unrelated requests, increasing the likelihood of accidental skill execution. In this skill's context, unintended activation matters because execution entails scanning local session files that may contain sensitive historical metadata.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
This script emits user-facing text in Chinese and formats large numbers using Chinese units like '亿' and '万', while the CLI offers no language or locale selection. That creates a natural-language locale policy issue because the skill enforces a specific language presentation rather than offering a choice.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The human-readable report headings and labels are hard-coded in Chinese, and there is no documented opt-in or locale selector for users who need a different language. Under the policy, forcing a specific language in user-facing natural-language output is a reportable issue unless the locale restriction is clearly justified.

Static analysis

No suspicious patterns detected.