Back to skill

Security audit

Token Monitor

Security checks for vulnerabilities and agentic risk

Overview

This quota-monitoring skill is mostly purpose-aligned, but its shell script has real validation gaps that could allow command execution or unintended file overwrite when run with untrusted configuration.

Review this skill before installing in automated or privileged contexts. Use fixed numeric thresholds, do not pass threshold or state-file values from untrusted environments, keep the state directory private to the monitoring user, and avoid heartbeat wrappers that forward raw stderr without review or redaction.

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

Error
Location
scripts/check-quota.sh:7
Finding

Command Execution Through Unvalidated Arithmetic Threshold

Content
View full analysis
"$STATE_FILE" ``` ### Technical Analysis `THRESHOLD` can be supplied through either the `QUOTA_THRESHOLD` environment variable or the `--threshold` argument. The script does not verify that the value is a decimal integer within the expected percentage range. The value is subsequently used as an operand in Bash's arithmetic comparison: ```bash [[ $quota_pct -lt $THRESHOLD ]] ``` Values evaluated in a Bash arithmetic context are treated as arithmetic expressions rather than inert strings. Bash can recursively resolve variable references and evaluate array-subscript expressions. Crafted expressions containing an array reference whose subscript includes command substitution can consequently cause a command to run when the comparison is evaluated. The value is also concatenated into the `jq` filter instead of being passed as a data argument. Although this second use will commonly produce a `jq` syntax error for malformed input, dynamically constructing the filter unnecessarily expands the injection surface. ### Atta ...[truncated 1413 chars]
Remediation
View remediation
&2 exit 2 fi ``` Convert the validated value explicitly using a decimal base before comparison: ```bash THRESHOLD_NUM=$((10#$THRESHOLD)) if (( 10#$quota_pct < THRESHOLD_NUM )); then LOW_QUOTAS+=("${provider} ${quota_name}: ${quota_pct}% left") fi ``` Do not concatenate the threshold into the `jq` filter. Pass it as typed data: ```bash jq -n \ --argjson warned "$(printf '%s\n' "${LOW_QUOTAS[@]}" | jq -R . | jq -s .)" \ --argjson current "$(printf '%s\n' "${CURRENT_QUOTAS[@]}" | jq -R . | jq -s .)" \ --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --argjson threshold "$THRESHOLD_NUM" \ '{ warned: $warned, current: $current, lastCheck: $timestamp, threshold: $threshold }' > "$STATE_FILE" ``` Scheduled invocations should additionally use a controlled environment and fixed arguments rather than inheriting configuration from an untrusted caller. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/check-quota.sh:8
Finding

Arbitrary File Replacement Through Unrestricted State Path and Symlink Following

Content
View full analysis
"$STATE_FILE" ``` ### Technical Analysis The state-file destination is accepted without restriction from `QUOTA_STATE_FILE` or `--state-file`. The script creates the destination's parent directories and then opens the selected path with shell output redirection. Shell redirection follows an existing symbolic link. The script does not verify that the destination is a regular file, that it is owned by the expected account, or that it resides within an approved state directory. It also does not use protected, atomic file creation. Consequently, a caller who controls the configured path can select any location writable by the monitoring identity. Separately, a local attacker who can modify the state directory can replace the expected state file with a symbolic link before execution. The next run will truncate the linked target and replace its contents with quota-state JSON. The content written is not fully attacker-selected, so this is a constrained arbitrary-file replacement rather than unrestricted arbitrary-content writing. Nevertheless, truncating or replacing configuration and data files can cause denial of service or security-relevant integrity loss. ### Attack Path ...[truncated 1559 chars]
Remediation
View remediation
&2 exit 2 fi if [[ -e "$STATE_FILE" && ! -f "$STATE_FILE" ]]; then printf 'State path is not a regular file\n' >&2 exit 2 fi ``` Set restrictive permissions and write atomically through a temporary file created inside the trusted directory: ```bash umask 077 tmp_file=$(mktemp -- "$STATE_DIR/.token-state.XXXXXX") trap 'rm -f -- "$tmp_file"' EXIT jq ... > "$tmp_file" chmod 600 -- "$tmp_file" mv -fT -- "$tmp_file" "$STATE_FILE" trap - EXIT ``` The trusted state directory must not be writable by less privileged users. For privileged cron execution, use fixed configuration and verify directory and file ownership before every write. ]]>
Vulnerability Patterns
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (5)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% 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 · SKILL.md (reported line 48)May include surrounding context.

Optional cleanup (state)

bash
rm -f ~/.openclaw/workspace/skills/token-monitor/.token-state.json

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The documentation claims the skill does not handle secrets, yet the Heartbeat example captures both stdout and stderr (2>&1) and forwards any non-empty output in a wake event. If openclaw models status, the script, or a dependency emits tokens, account identifiers, debug data, or environment-derived error messages, that content could be propagated outside the local context despite the safety claim.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

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

Automated Monitoring (Cron Job)

Create a dedicated cron job for precise scheduling:

bash
openclaw cron add --schedule "*/30 * * * *" \

Session Persistence

Medium
Category
Rogue Agent
Confidence
55% 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.

Content

Scanner excerpt · scripts/check-quota.sh (reported line 67)May include surrounding context.

sh
fi
done <<< "$STATUS_OUTPUT"

# Load previous state
PREVIOUS_WARNINGS=()
if [[ -f "$STATE_FILE" ]]; then
  # Read previous warnings (one per line)

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

At L169 the documentation states the script itself uses openclaw cron wake, implying an active alert-delivery side effect. However, the usage examples at L085-L096 show the script's output is consumed by another wrapper which performs openclaw cron wake, so the description contradicts the actual documented execution model.

Content

No source excerpt is available for this finding.