Back to skill

Security audit

AI Expense Tracker

Security checks for vulnerabilities and agentic risk

Overview

This expense tracker is purpose-aligned overall, but it asks the agent to run shell-style commands with user-supplied expense text, which creates a real command-injection review concern.

Review before installing. Use only for deliberate Vietnamese expense-tracking workflows, and avoid entering untrusted or adversarial text until the command invocation is changed to structured arguments with validation and confirmation. Be aware that spending records and report images are stored locally in plaintext.

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

Error
Location
SKILL.md:10
Finding
Shell Command Injection Through User-Controlled Expense Arguments<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 10-12 **Vulnerability Type**: Shell command injection caused by unsafe interpolation of user-controlled values **Risk Level**: High ### Vulnerable Code Snippet ```text - Extract the amount (`amount`), category (`category`), and description (`desc`). - Call: python3 /home/hoang/.openclaw/workspace/expense-tracker/scripts/finance_manager.py log --amount <amount> --category <category> --desc "<description>" ``` ### Technical Analysis The skill instructs the agent to construct an `exec` command by directly interpolating expense data extracted from the user's message. The dynamic `amount` and `category` arguments are unquoted, while `desc` is only enclosed in double quotes. Double quotes do not prevent shell evaluation of command substitutions such as `$(command)` or backticks. A description containing an embedded quote may also terminate the intended argument and introduce additional shell syntax. Unquoted category or amount values provide further injection opportunities if the agent does not strictly validate them before constructing the command. The Python script's use of `argparse` does not mitigate this vulnerability because shell parsing and command substitution occur before Python receives the argument list. ### Attack Path 1. An attacker submits an expense-recording request containing a crafted field, for example a description equivalent to `$(touch /tmp/expense-skill-pwned)`. 2. The agent extracts the crafted text as the expense description. 3. Following `SKILL.md`, the agent interpolates it into the documented shell command: ```sh python3 /home/hoang/.openclaw/workspace/expense-tracker/scripts/finance_manager.py log --amount 50000 --category Food --desc "$(touch /tmp/expense-skill-pwned)" ``` 4. If `exec` invokes a shell, the shell evaluates the command substitution before launching `finance_manager.py`. 5. The injected command executes with the operating-system pri ...[truncated 1009 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not construct a shell command by concatenating or interpolating user-controlled text. 2. Invoke the script through an API that accepts an argument array and disables shell processing: ```python subprocess.run( [ "python3", "/home/hoang/.openclaw/workspace/expense-tracker/scripts/finance_manager.py", "log", "--amount", validated_amount, "--category", validated_category, "--desc", description, ], shell=False, check=True, ) ``` 3. Update `SKILL.md` to explicitly require structured argument passing with no shell and prohibit interpolation into command strings. 4. Validate `amount` using a strict numeric parser and enforce an appropriate nonnegative range. 5. Restrict `category` to the documented allowlist: `Food`, `Drink`, `Transport`, `Shopping`, or `Other`. 6. Treat `desc` as opaque data. Do not attempt to make unsafe shell interpolation acceptable through ad hoc filtering. 7. If the execution interface can accept only shell text, apply a proven platform-specific shell-quoting routine independently to every dynamic argument. This is a fallback rather than the preferred design. 8. Add regression tests covering command substitutions, embedded quotes, semicolons, redirection operators, newlines, backticks, and option-like values. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (12)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill invokes local Python scripts through an execution tool but does not declare any explicit tool scope or allowed-tools constraints. That creates unnecessary ambiguity around what capabilities the skill may use and increases the chance of over-broad execution, file access, or unintended state changes beyond simple expense tracking.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The description is broad enough that the skill could activate on vague finance-related requests and then execute local scripts that modify persistent budget or expense records. Over-triggering is dangerous here because the skill is not purely conversational: it can cause real state changes and generate files without a clearly narrow activation boundary.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The manifest description and all example triggers are written in Vietnamese and instruct the assistant to respond in that mode, without offering any language choice. This can violate language/locale policy when users have not opted into Vietnamese or may prefer another language.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
These instructions direct the agent to execute scripts that can write persistent expense and budget data, but they do not warn about those side effects or require user confirmation. A user could unintentionally trigger data modification through natural language, leading to silent record changes or corrupted personal finance history.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill stores sensitive personal financial data to a local CSV file without any prior disclosure, consent flow, or explanation of where the data is retained. In a personal finance context, silent persistence increases privacy risk because spending descriptions, categories, and dates can reveal sensitive habits and may be exposed to other local users, backups, or later processes.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
Nearly all user-visible output strings are hard-coded in Vietnamese, including success, error, report, and budget messages. This imposes a specific language on all users without opt-in or justification, which matches the language/locale policy violation criteria.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The skill description explicitly says it can 'ĐẶT NGÂN SÁCH (budget tháng này)', which implies storing or enforcing a budget. In code, the budget branch only prints a success message marked '(Mô phỏng)' and does not persist or apply any budget data, so the implemented behavior does not match the claimed capability.

Missing User Warnings

Low
Confidence
81% confidence
Finding
The reporting flow returns a local chart_path and instructs the agent to send that file back to the user without describing this file-disclosure behavior. While expected in a reporting feature, undisclosed file handling can expose local path information and normalize sending local artifacts without validating that the file is the intended generated chart.

Missing User Warnings

Low
Confidence
87% confidence
Finding
Report generation writes a chart image file to disk without clearly notifying the user, creating an additional artifact containing potentially sensitive financial information. While lower risk than the main CSV storage, this still expands the data footprint and can leak private spending summaries through local file access or synced folders.

Intent-Code Divergence

Low
Confidence
96% confidence
Finding
The comment at L16 states that `expenses.csv` is stored 'ra ngoài workspace root' (outside the workspace root). However, the path calculation in L17-L18 goes up to the workspace root and then writes `expenses.csv` directly there, not outside it. This is a documentation-to-code contradiction, even though the impact is limited.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
This code contains natural-language text in Vietnamese in a comment and later emits Vietnamese-only success output, which indicates the skill is designed around a fixed language/locale. The policy allows locale constraints only when clearly documented and justified or when the user can opt in, neither of which is present in this file.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The success response string is emitted only in Vietnamese, forcing a specific language for user-visible output. There is no indication in the file that users can choose a language or that the locale restriction is documented as intentional and justified.

Static analysis

No suspicious patterns detected.