Back to skill

Security audit

Invoice

Security checks for vulnerabilities and agentic risk

Overview

The skill’s invoice workflow is mostly coherent, but its local scripts can execute unsafe user-influenced values and can overwrite existing invoice records despite the stated guardrails.

Review this skill before installing. Use only a dedicated private invoice repository and a short-lived fine-grained GitHub token limited to that repository. Do not allow arbitrary prefixes, years, or invoice numbers, and avoid using it for production invoices until the scripts validate inputs and refuse existing-file overwrites unless a separate explicit overwrite confirmation is implemented.

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
scripts/get-next-number.sh:30
Finding

Python Code Injection Through Unvalidated Invoice Prefix

Content
View full analysis
Remediation
View remediation
&2 exit 1 ;; esac ``` 2. Never interpolate shell variables into Python source. Pass them as arguments: ```bash NEXT_NUMBER=$(python3 -c ' import json import re import sys prefix = sys.argv[1] files = json.load(sys.stdin) pattern = re.compile(rf"{re.escape(prefix)}-(\d+)\.json$") # Process files here. ' "$PREFIX" <<< "$RESPONSE") ``` 3. Validate `YEAR` using a strict expression such as `^[0-9]{4}$`. 4. Validate `INVOICE_REPO` as an expected GitHub `owner/repository` identifier. 5. Add negative tests using prefixes containing quotes, newlines, backslashes, and Python syntax. 6. Continue using a fine-grained GitHub token limited to the single invoice repository. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/get-invoices.sh:42
Finding

Python Code Injection in Invoice Listing and Retrieval

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/push-invoice.sh:32
Finding

Existing Invoice Records Can Be Silently Overwritten

Content
View full analysis
/dev/null || echo "{}") EXISTING_SHA=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin).get('sha',''))" 2>/dev/null || echo "") # Build the API payload safely via python3 with sys.argv (no shell interpolation) PAYLOAD=$(python3 -c " import json, sys msg = sys.argv[1] b64 = sys.argv[2] sha = sys.argv[3] if len(sys.argv) > 3 else '' payload = { 'message': msg, 'content': b64, 'branch': 'main' } if sha: payload['sha'] = sha ``` ### Technical Analysis The script queries GitHub for an existing file and automatically includes its SHA in the subsequent Contents API request. Under GitHub's API semantics, including the existing SHA changes the operation from file creation to file update. Consequently, invoking the ordinary upload command for an existing invoice number silently overwrites that record. The script has no separate overwrite flag, no interactive confirmation, and no failure path for an existing file. This behavior contradicts the declared guardrail in `SKILL.md`, which states that an existing invoice must never be overwritten without explicit confirmation. A general confirmation to upload a newly previewed invoice is not equivalent to confirmation that an existing financial record will be replaced. ### Attack Path 1. A duplicate invoice number is selected because of a numbering race, stale repository state, operator error, or manipulated Agent input. 2. The user confirms the normal upload operation while believing a new file will be created. 3. ...[truncated 995 chars]
Remediation
View remediation
&2 exit 1 fi ``` 2. If updates are required, introduce a separate explicit option such as `--overwrite` and require the Agent to obtain dedicated user confirmation that clearly identifies the existing record. 3. Keep overwrite logic in a separate command or code path so that normal invoice creation cannot accidentally update existing content. 4. Validate `PREFIX`, `YEAR`, and `NUMBER` before constructing `FILE_PATH`. 5. Recheck file existence immediately before creation and handle GitHub conflict responses to mitigate concurrent numbering races. 6. Consider an immutable invoice workflow: create correction or cancellation documents instead of modifying previously issued invoices. 7. Record any authorized update with a clear commit message describing that an existing invoice was changed and by whom. ]]>
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The documented behavior promises sequential numbering and preview generation, but those controls are delegated to external scripts that are not declared or validated here, while credential and repository access are still required. This mismatch makes the skill harder to audit and may cause operators to trust safeguards that are not actually guaranteed by the visible skill definition.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
84% confidence
Finding

The documented behavior promises sequential numbering and preview generation, but those controls are delegated to external scripts that are not declared or validated here, while credential and repository access are still required. This mismatch makes the skill harder to audit and may cause operators to trust safeguards that are not actually guaranteed by the visible skill definition.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
./scripts/push-invoice.sh <PREFIX> <YEAR> <NUMBER> '<JSON>'

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
./scripts/push-invoice.sh <PREFIX> <YEAR> <NUMBER> '<JSON>'

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
**Repository visibility:** The target GitHub repository (`INVOICE_REPO`) SHOULD be **private**. It will contain invoice JSON files with business-sensitive data.

**Credential scope:** Use a **fine-grained GitHub Personal Access Token** scoped to the single target repository with only:
- `contents: write` (to push JSON files)
Do NOT use a classic PAT with broad `repo` scope. Limit the token lifetime and rotate regularly.

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

The skill requires a GitHub Personal Access Token with contents:write access, which is a powerful credential that can modify repository contents if mishandled. In combination with the declared network and exec permissions, compromise of the skill logic or scripts could misuse the token to alter, overwrite, or exfiltrate invoice data or other accessible repository content.

Content

Scanner excerpt · claw.json (reported line 20)May include surrounding context.

json
"env": [
    {
      "name": "GITHUB_TOKEN",
      "description": "GitHub Personal Access Token with contents:write permissions",
      "required": true
    },
    {

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill explicitly instructs the agent to execute shell scripts, but it does not declare any tool scope such as allowed-tools or permissions. This creates an overbroad execution surface where an agent runtime may permit shell access without a narrowly documented boundary, increasing the risk of unintended command execution or abuse if surrounding inputs are manipulated.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
If the user provides all information in a single message, proceed directly. If information is missing, ask concisely.

**Sender details** are always the same (from `data.json` or previous invoices). Do NOT ask the user for sender details. Load them from the most recent invoice or `data.json` in the repository.

### Step 2: Determine Invoice Number

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
If the user provides all information in a single message, proceed directly. If information is missing, ask concisely.

**Sender details** are always the same (from `data.json` or previous invoices). Do NOT ask the user for sender details. Load them from the most recent invoice or `data.json` in the repository.

### Step 2: Determine Invoice Number

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
**Key details:**

- **`sender`** -- Your company data. Loaded from `data.json` or a previous invoice in the repository. Never ask the user for this.
- **`meta.id`** -- Document ID, e.g. `RE-6007` or `AN-6002`
- **`meta.title`** -- Supports `{id}` template substitution (e.g. `"Rechnung Nr. {id}"` becomes `"Rechnung Nr. RE-6007"`)
- **`meta.date`** -- German date format `DD.MM.YYYY`

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The skill mandates German date formatting and elsewhere provides fixed German phrasing for invoices and Telegram responses, but it does not offer users a language or locale choice. This is a natural-language locale policy issue because the skill effectively enforces a specific language/formatting convention without opt-in or explicit region-scoped justification.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
## Guardrails

- ALWAYS determine the next invoice number automatically (NEVER ask the user)
- ALWAYS use `calc-preview.sh` for the preview (NEVER calculate totals yourself)
- ALWAYS show a preview before uploading
- NEVER put calculated totals in the JSON (no `netTotal`, `taxAmount`, `grossTotal` in items or totals)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
76% confidence
Finding

The tag "german" and the German-specific example "Rechnung" indicate a locale focus. Because the manifest does not state that this is optional, user-selectable, or justified as a region-specific skill, it may impose a language/locale constraint without opt-in.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The skill's purpose is creating and managing invoice JSON files on GitHub, which clearly justifies network access to GitHub. However, the manifest also requests "exec" capability, and nothing in the stated purpose explains why arbitrary command execution is necessary; PDF generation via GitHub Actions happens remotely and does not inherently require local execution privileges.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The example flow has the assistant upload invoice data to GitHub and notes that an automated action will build a PDF and email it, but it does not warn the user that customer PII and billing details will be transmitted to external systems. This creates a meaningful privacy and consent risk because users may approve the upload without understanding the disclosure or downstream processing of sensitive business data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

This markdown file demonstrates listing invoices, showing a specific invoice, and preparing an offer containing customer identity and address details. The examples do not include any user-facing warning about exposing or processing sensitive financial/customer data, which is relevant for markdown files that describe behaviors affecting privacy.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script hard-codes German locale formatting and German user-facing text, including the currency formatter docstring ('German EUR string') and all output labels/prompts such as 'Angebot', 'Rechnung', and 'Soll ich die Rechnung hochladen?'. This enforces a specific language/locale without offering opt-in or configuration, which matches the policy-violation category for locale/language constraints.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script performs an authenticated HTTP request using the GITHUB_TOKEN environment variable, which is a sensitive credential and transmits it to an external service. While the code comments describe functionality, there is no explicit warning, confirmation, or user-facing disclosure about using a credential for network access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The Authorization header directly uses GITHUB_TOKEN, which is a sensitive environment variable. The script validates INVOICE_REPO but does not similarly disclose or explain that a GitHub access token is required and will be used for authenticated API access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This branch also makes an authenticated network request using GITHUB_TOKEN to retrieve repository contents from GitHub. As with the earlier call, there is no visible confirmation, warning, or disclosure to the user that the script will use credentials and contact an external service.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/get-invoices.sh (reported line 26)May include surrounding context.

sh
# List files in the year directory
RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github.v3+json" \
  "https://api.github.com/repos/$REPO/contents/$DIR_PATH?ref=main" 2>/dev/null)

# Extract the highest invoice number from filenames
NEXT_NUMBER=$(python3 -c "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/get-invoices.sh (reported line 40)May include surrounding context.

sh
# List files in the year directory
RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github.v3+json" \
  "https://api.github.com/repos/$REPO/contents/$DIR_PATH?ref=main" 2>/dev/null)

# Extract the highest invoice number from filenames
NEXT_NUMBER=$(python3 -c "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/get-next-number.sh (reported line 25)May include surrounding context.

sh
# List files in the year directory
RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github.v3+json" \
  "https://api.github.com/repos/$REPO/contents/$DIR_PATH?ref=main" 2>/dev/null)

# Extract the highest invoice number from filenames
NEXT_NUMBER=$(python3 -c "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/push-invoice.sh (reported line 35)May include surrounding context.

sh
# List files in the year directory
RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github.v3+json" \
  "https://api.github.com/repos/$REPO/contents/$DIR_PATH?ref=main" 2>/dev/null)

# Extract the highest invoice number from filenames
NEXT_NUMBER=$(python3 -c "

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/push-invoice.sh (reported line 59)May include surrounding context.

sh
# List files in the year directory
RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github.v3+json" \
  "https://api.github.com/repos/$REPO/contents/$DIR_PATH?ref=main" 2>/dev/null)

# Extract the highest invoice number from filenames
NEXT_NUMBER=$(python3 -c "

Static analysis

No suspicious patterns detected.