T09 · Insecure Skill Coding Practices
- Location
token_stats/file_manager.py:382- Finding
Arbitrary Recursive Directory Deletion Through User-Controlled Install Path
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is mainly a local token-usage viewer, but its maintenance commands can modify PATH, update itself, and delete directories with insufficient safeguards.
Install only if you are comfortable with a tool that edits your shell PATH, creates persistent wrappers, reads local agent usage/history files, and can update or uninstall itself. Avoid custom --install-dir values for uninstall, review any directory it says it will remove, and treat CSV exports as untrusted when opening them in spreadsheet software.
token_stats/file_manager.py:382Arbitrary Recursive Directory Deletion Through User-Controlled Install Path
token_stats/exporters.py:616CSV Formula Injection Through Untrusted Model Names
README.md:58Unpinned Globally Installed ClawHub Dependency Creates Supply-Chain Exposure
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
s above.
Cause 2: Ran setup but haven't opened a new terminal → setup writes PATH to system config. Open a new terminal for it to take effect.
Cause 3: setup PATH write failed → Re-run setup and check for errors. If needed, add PATH manually:
macOS (zsh):
echo 'export PATH="$HOME/.token-stats/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
Linux (bash):
echo 'export PATH="$HOME/.token-stats/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Windows (PowerShell, current session only):
$env:PATH += ';' + "$env:USERPROFILE\.token-stats\bin"
Permission denied when running token-statsmacOS / Linux only. Cause: wrapper script lacks execute permission.
chmod +x ~/.token-stats/bin/token-stats
# Or just re-run setup
python3 ~/skills/agent-usage-stats/token-stats.py setup
Windows users are not affected (
.cmdfiles don't need execute permission).
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
s above.
Cause 2: Ran setup but haven't opened a new terminal → setup writes PATH to system config. Open a new terminal for it to take effect.
Cause 3: setup PATH write failed → Re-run setup and check for errors. If needed, add PATH manually:
macOS (zsh):
echo 'export PATH="$HOME/.token-stats/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
Linux (bash):
echo 'export PATH="$HOME/.token-stats/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Windows (PowerShell, current session only):
$env:PATH += ';' + "$env:USERPROFILE\.token-stats\bin"
Permission denied when running token-statsmacOS / Linux only. Cause: wrapper script lacks execute permission.
chmod +x ~/.token-stats/bin/token-stats
# Or just re-run setup
python3 ~/skills/agent-usage-stats/token-stats.py setup
Windows users are not affected (
.cmdfiles don't need execute permission).
System-directory installation, global wrapper creation/deletion, PATH updates, config removal, and external update calls are materially different from simply displaying token statistics. In the context of an agent skill, this creates a trust gap where a low-risk utility may receive approval despite having the ability to change execution environment and remove files.
System-directory installation, global wrapper creation/deletion, PATH updates, config removal, and external update calls are materially different from simply displaying token statistics. In the context of an agent skill, this creates a trust gap where a low-risk utility may receive approval despite having the ability to change execution environment and remove files.
System-directory installation, global wrapper creation/deletion, PATH updates, config removal, and external update calls are materially different from simply displaying token statistics. In the context of an agent skill, this creates a trust gap where a low-risk utility may receive approval despite having the ability to change execution environment and remove files.
System-directory installation, global wrapper creation/deletion, PATH updates, config removal, and external update calls are materially different from simply displaying token statistics. In the context of an agent skill, this creates a trust gap where a low-risk utility may receive approval despite having the ability to change execution environment and remove files.
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
env: dict[str, str] | None = None, expect: list[str] | None = None,
allow_fail: bool = False, cwd: Path | str | None = None) -> subprocess.CompletedProcess:
print(f"$ {' '.join(str(c) for c in cmd)}")
run_env = os.environ.copy()
run_env.setdefault("PYTHONIOENCODING", "utf-8")
if env:
run_env.update(env)
Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.
calls_expr = "SUM(api_call_count)" if has_api_calls else "0"
tools_expr = "SUM(tool_call_count)" if has_tool_calls else "0"
cur = conn.execute(
f"SELECT model, SUM(input_tokens) as inp, SUM(output_tokens) as out, "
f"SUM(cache_read_tokens) as cache, {calls_expr} as calls, "
f"{tools_expr} as tools, COUNT(*) as cnt "
Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.
calls_expr = "SUM(api_call_count)" if has_api_calls else "0"
tools_expr = "SUM(tool_call_count)" if has_tool_calls else "0"
cur = conn.execute(
f"SELECT model, SUM(input_tokens) as inp, SUM(output_tokens) as out, "
f"SUM(cache_read_tokens) as cache, {calls_expr} as calls, "
f"{tools_expr} as tools, COUNT(*) as cnt "
The code performs recursive deletion of install and legacy directories with no confirmation in this function. Destructive operations like shutil.rmtree are high risk because a wrong path, unexpected legacy path match, or maliciously influenced arguments could lead to irreversible data loss beyond the intended skill files.
The finding is valid, though the root issue is not SQL output injection in the usual sense; it is unsafe code construction. The SQL and surrounding Python are assembled into a python3 -c string using interpolated values (linux_path, where), so attacker-controlled path or timestamp-derived content can alter the executed Python/SQL payload, leading to arbitrary code execution in WSL or unintended database queries.
"cols={r[1] for r in c.execute('PRAGMA table_info(sessions)')};"
"has_ac='api_call_count' in cols;has_tc='tool_call_count' in cols;"
"ac='api_call_count' if has_ac else '0';tc='tool_call_count' if has_tc else '0';"
"rows=[dict(r) for r in c.execute("
"f'SELECT model,SUM(input_tokens) inp,SUM(output_tokens) out,SUM(cache_read_tokens) cache,'"
"f'SUM('+ac+') calls,SUM('+tc+') tools,COUNT(*) cnt FROM sessions%s GROUP BY model')];"
"sc=c.execute('SELECT COUNT(*) FROM sessions%s').fetchone()[0];"
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.
| | `--compare` / `--a` / `--b` | Compare two periods |
| | `--now` / `--detail` | Current snapshot / detail mode, same as default stats |
| `--all` | | View **all** agents at once |
| | `setup` / `--setup` | Install to `~/.token-stats/`, create `~/.token-stats/bin/token-stats`, and add it to PATH |
| | `update` / `--update` | Update to the latest version |
| | `--uninstall` | Remove wrapper, install directory, and PATH entry |
The documented behavior says --uninstall automatically removes multiple classes of files and PATH entries across platforms, which is an autonomous destructive action. In the context of an installable agent skill, automatically deciding to delete install/history directories can cause unintended data loss or overbroad cleanup if path handling is wrong or users do not understand the scope.
token-stats --uninstall
> `--uninstall` automatically removes wrappers, cleans PATH entries, deletes config files, removes `~/.token-stats/`, and clears ClawHub/history install directories such as `~/skills/agent-usage-stats` so reinstall can start cleanly. Works on all platforms.
---
The documentation at L112 says users must manually delete ~/skills/agent-usage-stats/ to remove the ClawHub-downloaded files, but L602 states --uninstall automatically clears those install directories as well. These statements actively contradict each other about whether uninstall affects the original downloaded skill directory.
The README documents an uninstall command that may automatically remove wrappers, PATH entries, config files, install directories, and ClawHub/history directories without a prominent warning before the command is presented. Destructive file deletion and environment modification are risky because users may run the command expecting a narrow uninstall and unintentionally lose downloaded skill content or local state.
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.
Cause 2: Ran setup but haven't opened a new terminal → setup writes PATH to system config. Open a new terminal for it to take effect.
Cause 3: setup PATH write failed → Re-run setup and check for errors. If needed, add PATH manually:
macOS (zsh):
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.
Cause: the directory path you entered doesn't exist. Create it first:
mkdir -p ~/Desktop/my-data
The description around '只读本机 SQLite / JSONL' and '本地账本' frames the skill as a read-only usage viewer. Yet the README documents operational commands that write into ~/.token-stats/, create global launchers, add PATH entries, and remove files/directories during uninstall, which is materially beyond passive statistics reading.
The README states token-stats '不联网、不查 API 后台,纯读当前设备上的数据文件', which communicates a strongly local, read-only scope. However, elsewhere the same file documents token-stats update and ClawHub/npm installation/update operations that necessarily contact remote package sources, so the documented behavior is broader than the stated 'no network' claim.
The README describes uninstall behavior that removes wrappers, PATH entries, configuration, installation directories, and historical skill directories, but does not present a strong warning, confirmation step, or precise deletion scope at the point of use. Destructive file-removal operations can cause accidental data loss or overbroad cleanup if users do not understand exactly what will be deleted.
The skill metadata declares no explicit tool scope or permissions, yet the referenced behavior includes file access, shell execution, environment access, and possible network/update operations. In an agent ecosystem, missing scope declarations weakens user consent and sandboxing expectations, making it easier for a seemingly simple stats skill to perform broader local actions than its description suggests.
The manifest description on L03 forces a specific language presentation, and the rest of the skill documentation continues in Chinese. Under the policy, language constraints should either be optional for the user or clearly justified as region-specific, which is not stated here.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if env:
run_env.update(env)
try:
result = subprocess.run(
[str(c) for c in cmd],
capture_output=True,
text=True,
This code file contains natural-language CLI documentation and help output that forces a specific language/locale for all users. Under the policy, locale constraints should either offer user opt-in/choice or be clearly justified as region-specific, which is not present here.
The manifest description frames this skill as a read-oriented monitoring tool for selecting an AI assistant and viewing token usage. In addition to analytics, the code exposes setup, update, and uninstall flows that create/remove installation directories, global commands, and PATH entries, which is broader than the stated purpose of viewing usage statistics.
No suspicious patterns detected.