Back to skill

Security audit

Finance Skill

Security checks for vulnerabilities and agentic risk

Overview

This finance skill is purpose-aligned, but it needs Review because it persistently stores sensitive bank data without strong local protection or clear confirmation controls.

Install only if you are comfortable storing bank statements and transaction history locally in the OpenClaw workspace. Before using it, consider tightening permissions on ~/.openclaw/workspace/finance, avoiding raw statement retention unless needed, and requiring confirmation before the agent adds manual transactions.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/add-transactions.sh:5
Finding
Sensitive Financial Records Created Without Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/add-transactions.sh`, lines 5–13 **Vulnerability Type**: Sensitive data exposure through insecure filesystem permissions **Risk Level**: Medium ### Vulnerable Code ```bash FINANCE_DIR="${HOME}/.openclaw/workspace/finance" STORE="${FINANCE_DIR}/transactions.json" SOURCE="${1:-manual}" mkdir -p "$FINANCE_DIR/statements" # Initialize store if doesn't exist if [ ! -f "$STORE" ]; then echo '{"transactions":[],"accounts":[]}' > "$STORE" fi ``` ### Technical Analysis The script stores transaction dates, merchant names, monetary amounts, categories, source documents, and account metadata in a local JSON file. It does not establish a restrictive `umask` or explicitly set permissions on the finance directories and transaction file. Consequently, permissions depend entirely on the invoking process's environment. With a common `umask` of `022`, directories can be created as `0755` and the transaction file as `0644`. This may permit other local users to traverse the finance directories and read the financial records. The script also does not verify that existing storage paths are owned by the current user or that they are not symbolic links. ### Attack Path 1. A user invokes `add-transactions.sh` to import financial transactions. 2. The script creates the finance directories and `transactions.json` using the caller's default `umask`. 3. The resulting file is created with permissions that may allow access by other local users. 4. Another local account or process reads `~/.openclaw/workspace/finance/transactions.json`. 5. The attacker obtains the user's transaction history and any stored account metadata. ### Impact Assessment A local attacker may disclose sensitive financial information, including spending amounts, merchants, dates, categories, statement source names, and account details. The issue does not directly grant elevated system privileges, but it compromises the confidentiality of all fin ...[truncated 190 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Set a restrictive process mask before creating any finance data: ```bash umask 077 ``` 2. Explicitly create storage directories with owner-only permissions: ```bash mkdir -p -m 700 "$FINANCE_DIR" mkdir -p -m 700 "$FINANCE_DIR/statements" ``` 3. Create the transaction file with mode `0600`, and correct permissions on existing files: ```bash if [ ! -e "$STORE" ]; then printf '%s\n' '{"transactions":[],"accounts":[]}' > "$STORE" fi chmod 600 "$STORE" ``` 4. Before reading or replacing existing paths, verify that they: - Are owned by the effective user. - Are regular files or directories of the expected type. - Are not symbolic links. - Are not writable by group or other users. 5. Fail securely if the ownership or permissions do not meet these requirements. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/add-transactions.sh:19
Finding
Predictable Temporary File Enables Symlink-Based File Clobbering<![CDATA[ ## Vulnerability Details **File Location**: `scripts/add-transactions.sh`, lines 19–22 **Vulnerability Type**: Unsafe predictable temporary file **Risk Level**: Medium ### Vulnerable Code ```bash jq --arg source "$SOURCE" --arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --argjson new "$NEW_TXS" \ '.transactions += ($new | map(. + {source: $source, added: $now, id: (now | tostring + "-" + (. | @base64 | .[0:8]))}))' \ "$STORE" > "${STORE}.tmp" && mv "${STORE}.tmp" "$STORE" ``` ### Technical Analysis The script writes updated transaction data to the fixed path `transactions.json.tmp`. Shell output redirection opens this path before `jq` executes and follows symbolic links by default. If an attacker can create or replace entries in the finance directory, the attacker can place a symbolic link at `${STORE}.tmp` that points to another file writable by the user running the script. When the script runs, redirection follows the link and truncates or overwrites the target with generated JSON data. The subsequent `mv` does not prevent the initial overwrite. The weakness is amplified if the finance directory has inappropriate permissions or is located in an environment where another process operating under the same account is untrusted. ### Attack Path 1. The attacker obtains the ability to create or replace files in `~/.openclaw/workspace/finance/`. 2. The attacker creates a symbolic link named `transactions.json.tmp` pointing to a target file writable by the victim. 3. The victim runs `add-transactions.sh`. 4. The shell follows the symbolic link while processing the output redirection. 5. The target file is truncated and overwritten with the output from `jq`. 6. The final `mv` may replace the transaction store with the symlink entry or otherwise leave the store corrupted. ### Impact Assessment The attacker can overwrite or corrupt files writable by the account invoking the script. The affected scope is bounded by that account's existing filesystem ...[truncated 369 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Ensure that the finance directory is owned by the current user and has mode `0700`. 2. Create a unique temporary file with `mktemp` inside the protected destination directory: ```bash umask 077 TMP_FILE=$(mktemp "${FINANCE_DIR}/transactions.json.tmp.XXXXXX") || exit 1 trap 'rm -f -- "$TMP_FILE"' EXIT HUP INT TERM jq --arg source "$SOURCE" \ --arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --argjson new "$NEW_TXS" \ '.transactions += ($new | map(. + {source: $source, added: $now, id: (now | tostring + "-" + (. | @base64 | .[0:8]))}))' \ "$STORE" > "$TMP_FILE" || exit 1 chmod 600 "$TMP_FILE" mv -f -- "$TMP_FILE" "$STORE" || exit 1 trap - EXIT HUP INT TERM ``` 3. Validate that the existing store is a regular file owned by the invoking user and reject symbolic links. 4. Keep the temporary file on the same filesystem as the destination so that the final rename remains atomic. 5. Add error handling so failed writes do not leave stale temporary files or a partially updated store. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:91
Finding
Unpinned Third-Party Python Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 91–93; also documented in `README.md`, lines 65–69 **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Low ### Vulnerable Code ```markdown ## Dependencies - `jq` — for JSON transaction storage and querying (`apt install jq` / `brew install jq`) - `pypdf` — for full PDF text extraction (`pip3 install pypdf`) ``` The corresponding README requirement is: ```markdown ## Requirements - OpenClaw - `jq` (`apt install jq` / `brew install jq`) - Python 3 with `pypdf` (`pip3 install pypdf`) ``` ### Technical Analysis The installation guidance instructs users to install `pypdf` without a version constraint or cryptographic hash. Package resolution therefore depends on the mutable state of the configured Python package index at installation time. No suspicious package name or third-party index was identified, and the package name is consistent across the project. Nevertheless, the absence of a reviewed version lock means a compromised, malicious, or behaviorally incompatible future release could be installed automatically. Python package installation can execute package build or installation logic in the context of the invoking user. ### Attack Path 1. A user follows the documented setup instructions. 2. The user executes `pip3 install pypdf`. 3. `pip` resolves whichever release is current through the user's configured package index. 4. If that release or the package-distribution channel has been compromised, malicious installation or runtime code executes. 5. The malicious dependency receives the invoking user's privileges and may access statement files processed by the skill. ### Impact Assessment A compromised dependency could execute code with the privileges of the user performing installation or running statement extraction. It could potentially read financial statements, access other files available to that account, alter extracted data, or communicate data extern ...[truncated 267 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `pypdf` to a reviewed, known-good version in a requirements file: ```text pypdf==<reviewed-version> ``` 2. Generate and enforce cryptographic hashes: ```text pypdf==<reviewed-version> \ --hash=sha256:<verified-distribution-hash> ``` Install it with: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` 3. Install dependencies in a dedicated virtual environment rather than the system Python environment. 4. Commit the reviewed dependency manifest to the project and update both `SKILL.md` and `README.md` to reference it. 5. Periodically review pinned versions for security advisories and update pins and hashes through a controlled process. ]]>
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Missing User Warnings

High
Confidence
95% confidence
Finding
The skill directs the agent to persist highly sensitive financial records, including statements and transaction history, under a workspace path without any explicit warning, consent flow, retention policy, or privacy controls. Because financial data is particularly sensitive, silent persistence increases the risk of unintended long-term storage, overcollection, local disclosure to other tools or users on the system, and user surprise about where their data is being kept.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The README explicitly states that original bank statements and transaction history are retained on disk, but it does not warn users about the sensitivity, persistence, or local compromise risks of storing financial records unencrypted. In the context of a finance skill, this increases exposure to privacy loss and secondary compromise if the host, backups, shared account, or workspace permissions are weak.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The instruction to treat a casual natural-language statement like "I spent $X at Y" as a direct write operation to persistent storage is overly broad and can misfire on hypothetical, quoted, historical, or exploratory conversation. In a finance skill, that creates integrity risks by silently recording false transactions, which can corrupt spending history and downstream answers.

Static analysis

No suspicious patterns detected.