Back to skill

Security audit

AgentMeter

Security checks for vulnerabilities and agentic risk

Overview

The skill broadly matches its spend-tracking purpose, but it makes lasting Claude configuration changes and has unsafe argument and sync handling that users should review before installing.

Install only if you are comfortable with a skill that edits your project Claude settings, adds a Stop hook for ongoing tracking, reads Claude transcript metadata, and stores spend history locally. Use dashboard sync only with the default trusted HTTPS endpoint and a revocable API key, and avoid passing untrusted text as /meter arguments until argument validation is added.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:22
Finding

Shell Command Injection Through Unvalidated /meter Arguments

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
meter-sync.sh:34
Finding

Bearer Credential and Session Metadata Exposure Through an Unvalidated Sync Endpoint

Content
View full analysis
/dev/null) || HTTP_CODE="000" ``` The configured value is later loaded without validating its scheme or destination: ```bash API_KEY=$(jq -r '.api_key' "$SYNC_CONFIG") AGENT_NAME=$(jq -r '.agent_name' "$SYNC_CONFIG") ENDPOINT=$(jq -r '.endpoint' "$SYNC_CONFIG") ``` The same endpoint then receives the bearer credential and session records: ```bash RESPONSE=$(echo "$UNSYNCED" | jq -sc --arg agent "$AGENT_NAME" ' { agentName: $agent, sessions: [.[] | { id: .session_id, ts: .ts, api: .api, model: .model, project: .project, totalCalls: (.total_calls // 0), tokensIn: (.tokens_in // 0), tokensOut: (.tokens_out // 0), cacheCreation: (.cache_creation // 0), cacheRead: (.cache_read // 0), costUsd: (.cost_usd // 0), source: .source, purpose: (.purpose // null), intent: (.intent // null) }] } ' | curl -s -w "\n%{http_code}" \ -X POST \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d @- \ "$ENDPOINT/v1/sessions/batch") ``` ### Technical Analysis The setup workflow accepts an arbitrary endpoint and does not enforce HTTPS or validate the destination hostname. The script subsequently sends the API key in an `Authorization: Bearer` header to that endpoint during both verification and synchronization. If an `http://` endpoi ...[truncated 1881 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
meter-session-end.sh:106
Finding

Spend History Deletion Through Session ID Regex Injection

Content
View full analysis
/dev/null) || SESSION_ID="" TRANSCRIPT=$(echo "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null) || TRANSCRIPT="" CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null) || CWD="" ``` It is then interpolated into a regular expression used to remove records: ```bash # Dedup: remove any prior record for this session, then append the new one if grep -q "\"session_id\":\"$SESSION_ID\"" "$SPEND_FILE" 2>/dev/null; then grep -v "\"session_id\":\"$SESSION_ID\"" "$SPEND_FILE" > "$SPEND_DIR/spend_dedup.jsonl" || true mv "$SPEND_DIR/spend_dedup.jsonl" "$SPEND_FILE" fi cat "$SPEND_DIR/pending_${SESSION_ID}.jsonl" >> "$SPEND_FILE" rm -f "$SPEND_DIR/pending_${SESSION_ID}.jsonl" ``` ### Technical Analysis `grep` treats its search argument as a basic regular expression. Because `SESSION_ID` is inserted directly into that expression, metacharacters in a forged session ID alter the meaning of the match. For example, a session ID of `.*` produces a pattern equivalent to: ```text "session_id":".*" ``` This matches ordinary spend records containing a session ID. The subsequent `grep -v` removes every matching line, and `mv` replaces the original spend database with the filtered output. The new maliciously named record is then appended. The same unvalidated value is also included in temporary filenames. Although shell quoting prevents direct shell expansion, input validation is still required to prevent unsafe or unintended path components. ### Attack Path 1. An attacker invokes the hook directly or otherwise supplies crafted JSON on its standard i ...[truncated 1173 chars]
Remediation
View remediation
"$SPEND_DIR/spend_dedup.jsonl" ``` - If `grep` remains in use, use fixed-string matching with `grep -F`; JSON-aware comparison is still preferable. - Do not include untrusted identifiers directly in temporary filenames. Use `mktemp` in a protected directory. - Protect the read-modify-write sequence with a file lock to prevent concurrent hooks from losing records. - Write to a temporary file in the same directory and replace the destination atomically only after successful parsing. - Set restrictive permissions on `~/.agent-meter` and its data files. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (19)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill claims to track spend via /meter, but it also modifies local configuration, installs hooks for ongoing collection, and parses transcript files under ~/.claude/projects. Automatic persistence and hook registration are materially more invasive than the description suggests and can create lasting monitoring behavior users did not expect.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims to track spend via /meter, but it also modifies local configuration, installs hooks for ongoing collection, and parses transcript files under ~/.claude/projects. Automatic persistence and hook registration are materially more invasive than the description suggests and can create lasting monitoring behavior users did not expect.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill claims to track spend via /meter, but it also modifies local configuration, installs hooks for ongoing collection, and parses transcript files under ~/.claude/projects. Automatic persistence and hook registration are materially more invasive than the description suggests and can create lasting monitoring behavior users did not expect.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · meter-session-end.sh (reported line 111)May include surrounding context.

sh
mv "$SPEND_DIR/spend_dedup.jsonl" "$SPEND_FILE"
    fi
    cat "$SPEND_DIR/pending_${SESSION_ID}.jsonl" >> "$SPEND_FILE"
    rm -f "$SPEND_DIR/pending_${SESSION_ID}.jsonl"
  fi
fi

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill instructs the agent to execute bash, but the manifest declares no explicit tool scope or allowed-tools. That omission weakens least-privilege controls and makes it harder for users and platforms to understand that shell execution is required before invocation.

Content

No source excerpt is available for this finding.

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
85% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt · SKILL.md (reported line 31)May include surrounding context.

Install from ClawHub into your project:

bash
clawhub install agent-meter --dir .claude/skills

Then run /meter — it handles everything automatically:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The setup text minimizes the significance of copying hooks and modifying .claude/settings.json by framing it as automatic handling. Downplaying persistent file changes and hook registration reduces informed consent and increases the chance that users enable ongoing data collection unintentionally.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The hosted dashboard sync instructions do not prominently warn that local spend and session metadata will be transmitted off-machine. Without an explicit privacy disclosure, users may expose project names, model usage, timestamps, and other operational metadata to a third party unexpectedly.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The documentation asserts that components have no network calls or secrets access, while the same skill also offers dashboard sync that uses an API key and communicates with a remote service. Even if the statement is narrowly intended for specific scripts, the overall presentation is misleading and can cause unsafe trust decisions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script persists session identifiers, project names, model names, token counts, and estimated spend to a local JSONL file under the user's home directory without any notice, consent, retention control, or permission hardening shown in the script. While this appears intended for legitimate metering, the stored metadata can reveal work context and usage patterns, and becomes sensitive if the host is multi-user, backed up externally, or later exfiltrated by other software.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The setup flow provisions a remote account configuration and verifies an API key against a hosted endpoint, establishing authenticated exfiltration capability not implied by the stated local metering purpose. Even if intended for product functionality, this broadens trust boundaries and may surprise users who expect a purely local accounting tool.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · meter-sync.sh (reported line 53)May include surrounding context.

sh
--arg endpoint "$ENDPOINT" \
    '{ api_key: $key, agent_name: $name, endpoint: $endpoint }' > "$SYNC_CONFIG"

  chmod 600 "$SYNC_CONFIG"
  echo ""
  echo "Config saved to $SYNC_CONFIG"
  echo "Run 'meter-sync.sh' to sync."

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script transmits detailed per-session spend metadata, including project, model, source, purpose, and intent fields, to a remote service. That exceeds the skill description of showing local '/meter' spend summaries and creates a real data exposure risk because operational metadata can reveal sensitive project names, usage patterns, and user intent.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

This curl POST sends collected local session data to an external endpoint using a bearer token. External transmission is dangerous here because the payload contains detailed usage telemetry that may include sensitive business context, and the endpoint is user-configurable, increasing the risk of accidental or malicious redirection.

Content

Scanner excerpt · meter-sync.sh (reported line 150)May include surrounding context.

sh
intent: (.intent // null)
    }]
  }
' | curl -s -w "\n%{http_code}" \
  -X POST \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script advertised as a spend-summary entry point performs persistent system changes by installing a hook and mutating .claude/settings.json. That creates behavior beyond user-visible reporting, establishes ongoing execution on future Stop events, and can surprise users who invoked what appears to be a read-only utility.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Automatically wiring a Stop hook and editing settings as implicit side effects is unjustified for a command whose description suggests simple summarization. This persistence mechanism broadens the trust boundary because future sessions will execute the installed hook, which could later collect or alter more than the user expected.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script copies an executable into .claude/hooks and changes permissions without prior warning or confirmation. Silent installation of executable persistence is risky because users may not realize they have granted future execution to code from the skill package.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script scans local Claude transcript files and derives session metadata and token usage into a persistent spend database without an explicit warning. Even if intended for billing summaries, transcript-derived metadata such as session IDs, project names, timestamps, and model usage can expose sensitive work patterns and should not be harvested silently.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script silently enumerates local Claude transcript files under ~/.claude/projects and derives per-session metadata into a separate spend log without any notice, consent prompt, or visible disclosure during execution. While it does not exfiltrate data off-host, it processes potentially sensitive usage history and project identifiers, which can surprise users and create a privacy issue in an agent skill whose behavior may be triggered indirectly.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.