Back to skill

Security audit

Receipt Snap

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed receipt-tracking skill that stores expense records locally and in user-configured Google services, with privacy and feature-completeness caveats but no artifact-backed malicious behavior.

Install only if you are comfortable sending receipt files and expense metadata to the Google Drive folder and Google Sheet you configure, and keeping a local CSV copy. Verify the gog-authenticated Google account, folder ID, sheet ID, and RECEIPT_LOG_FILE path, and protect or disable the local log if the machine is shared.

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

Warning
Location
receipt_snap.py:122
Finding

Financial receipt metadata is stored in a plaintext CSV without restrictive permissions

Content
View full analysis

Vulnerability Details

File Location: receipt_snap.py, lines 122–136
Vulnerability Type: Plaintext storage of sensitive financial data with ambient filesystem permissions
Risk Level: Medium

python
def append_to_log(row_data):
    """Append row to local CSV log"""
    import csv as csv_module
    log_dir = os.path.dirname(LOG_FILE)
    if log_dir:
        os.makedirs(log_dir, exist_ok=True)

    header = ["Date", "Vendor", "Description", "Original Amount", "Currency",
              "EUR Amount", "Exchange Rate", "Category", "Drive Link", "Notes"]

    write_header = not os.path.exists(LOG_FILE)
    with open(LOG_FILE, 'a', newline='', encoding='utf-8') as f:
        writer = csv_module.writer(f)
        if write_header:
            writer.writerow(header)
        writer.writerow([str(x) for x in row_data])

Technical Analysis

The function writes receipt information to an unencrypted local CSV file. The stored fields include vendor names, descriptions, original and converted amounts, expense categories, Google Drive links, and free-form notes. This is sensitive financial and business information.

The file is created using Python's standard open() operation without explicitly setting owner-only permissions. Its effective permissions therefore depend on the process umask. On systems with a typical 022 umask, a newly created file may be readable by other local users. The function also does not inspect or correct the permissions of an existing log file.

The configured path is accepted without validating that the destination is a regular file rather than a symbolic link. Although exploitation depends on local filesystem access and directory permissions, this omission further weakens the safety of sensitive-data storage.

Attack Path

  1. The user processes a receipt with receipt_snap.py process.
  2. cmd_process() constructs a row containing financial metadata and calls append_to_log().
  3. append_to_log() creates or appends t ...[truncated 1024 chars]
Remediation
View remediation

Remediation Suggestions

  1. Create new log files atomically with owner-only permissions such as 0600, rather than relying on the process umask.
  2. Before appending, use os.lstat() to verify that the destination is a regular file and not a symbolic link.
  3. Check existing file permissions and reject or correct files readable or writable by group or other users.
  4. Create the containing directory with restrictive permissions such as 0700.
  5. Consider encrypting the local backup or making local CSV persistence opt-in because the same information is already sent to the configured Google Sheet.
  6. Document data retention, secure deletion, backup handling, and access-control expectations for the receipt log.

A hardened implementation can use os.open() with os.O_CREAT | os.O_APPEND | os.O_WRONLY and mode 0o600, then wrap the descriptor with os.fdopen(). Existing files should still be validated before use.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (21)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · README.md (reported line 56)May include surrounding context.

Copy .env.example to .env and fill in your values:

bash
cp .env.example .env
# Edit .env:
# RECEIPT_DRIVE_FOLDER_ID="1abc123XYZ..."
# RECEIPT_GOOGLE_SHEET_ID="1abc123XYZ..."

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill claims to automatically process receipt photos and PDFs, but the documented commands rely on manually supplied fields and also include undeclared local logging and extra commands. This mismatch can mislead users and orchestrators about what data is actually parsed, what is transmitted or stored, and what side effects occur, undermining informed consent and safe automation.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · README.md (reported line 139)May include surrounding context.

md
- RECEIPT_LOG_FILE (optional, defaults to ~/receipts/log.csv)

QUICK START:
  # Set env vars (or copy .env.example to .env and fill in)
  export RECEIPT_DRIVE_FOLDER_ID="your-folder-id"
  export RECEIPT_GOOGLE_SHEET_ID="your-sheet-id"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · README.md (reported line 140)May include surrounding context.

md
- RECEIPT_LOG_FILE (optional, defaults to ~/receipts/log.csv)

QUICK START:
  # Set env vars (or copy .env.example to .env and fill in)
  export RECEIPT_DRIVE_FOLDER_ID="your-folder-id"
  export RECEIPT_GOOGLE_SHEET_ID="your-sheet-id"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · receipt_snap.py (reported line 14)May include surrounding context.

python
- RECEIPT_LOG_FILE (optional, defaults to ~/receipts/log.csv)

QUICK START:
  # Set env vars (or copy .env.example to .env and fill in)
  export RECEIPT_DRIVE_FOLDER_ID="your-folder-id"
  export RECEIPT_GOOGLE_SHEET_ID="your-sheet-id"

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill invokes shell commands, accesses environment variables, performs network operations, and can write data externally, but it declares no explicit tool scope or permissions boundary. That makes its effective capabilities broader and less auditable, increasing the chance an agent could execute sensitive operations without clear user consent or policy enforcement.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The activation guidance is broad enough that an agent may trigger the skill on loosely related receipt, invoice, or tax-reporting conversations without strong user intent verification. Because the skill handles financial records and can upload data to third-party services, ambiguous triggering raises the risk of unintended processing or disclosure of sensitive documents.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill’s main description does not prominently warn that receipt images, extracted financial data, and metadata may be sent to Google Drive, Google Sheets, and an external exchange-rate service. For a finance-oriented workflow, failing to surface third-party transmission up front can cause users to disclose sensitive financial information without fully informed consent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Natural-language strings such as 'Process receipts for Spanish tax reporting' and the hardcoded Spanish category labels enforce a specific locale/language behavior. The file does not provide users with a choice of language/locale or a clearly documented opt-in mechanism for this constraint.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · receipt_snap.py (reported line 87)May include surrounding context.

python
return None

    filename = os.path.basename(file_path)
    result = subprocess.run(
        ["gog", "drive", "upload", file_path, "--parent", DRIVE_FOLDER_ID],
        capture_output=True, text=True
    )

Tainted flow: 'DRIVE_FOLDER_ID' from os.environ.get (line 42, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · receipt_snap.py (reported line 87)May include surrounding context.

python
return None

    filename = os.path.basename(file_path)
    result = subprocess.run(
        ["gog", "drive", "upload", file_path, "--parent", DRIVE_FOLDER_ID],
        capture_output=True, text=True
    )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · receipt_snap.py (reported line 104)May include surrounding context.

python
def rename_in_drive(file_id, new_name):
    """Rename file in Google Drive"""
    result = subprocess.run(
        ["gog", "drive", "rename", file_id, new_name],
        capture_output=True, text=True
    )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · receipt_snap.py (reported line 118)May include surrounding context.

python
return False

    values_json = json.dumps([[str(x) for x in row_data]])
    result = subprocess.run(
        ["gog", "sheets", "append", GOOGLE_SHEET_ID, "log!A:J",
         "--values-json", values_json, "--insert", "INSERT_ROWS"],
        capture_output=True, text=True

Tainted flow: 'GOOGLE_SHEET_ID' from os.environ.get (line 43, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · receipt_snap.py (reported line 118)May include surrounding context.

python
return False

    values_json = json.dumps([[str(x) for x in row_data]])
    result = subprocess.run(
        ["gog", "sheets", "append", GOOGLE_SHEET_ID, "log!A:J",
         "--values-json", values_json, "--insert", "INSERT_ROWS"],
        capture_output=True, text=True

Tainted flow: 'LOG_FILE' from os.environ.get (line 44, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
87% confidence
Finding

LOG_FILE is taken directly from an environment variable and then used for file creation/appending without path restrictions. In environments where untrusted parties can influence environment variables or deployment configuration, this can redirect sensitive receipt data to arbitrary filesystem locations or overwrite/append to unintended files accessible by the process.

Content

Scanner excerpt · receipt_snap.py (reported line 140)May include surrounding context.

python
"EUR Amount", "Exchange Rate", "Category", "Drive Link", "Notes"]

    write_header = not os.path.exists(LOG_FILE)
    with open(LOG_FILE, 'a', newline='', encoding='utf-8') as f:
        writer = csv_module.writer(f)
        if write_header:
            writer.writerow(header)

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest says the skill will process receipt photos and PDFs and extract vendor, date, amount, and currency. In code, the process command requires those fields to be passed explicitly as CLI arguments and only uses the file for upload/renaming, with no OCR, PDF parsing, or content extraction logic present.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The stated purpose includes processing receipt photos and screenshots, which implies image ingestion or OCR. The code only checks for file existence, uploads the file, and renames it; there is no image decoding, OCR, or screenshot handling behavior that would justify that claim.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill uploads receipt files to Google Drive and sends structured expense data to Google Sheets without an explicit privacy warning or consent checkpoint. In this context, the data includes potentially sensitive financial records, so transmitting it to external services can create compliance, confidentiality, and unintended sharing risks if users are unaware or if the configured accounts are wrong.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill persistently stores financial receipt metadata to a local CSV log without any explicit consent flow, retention control, or access protection. Because receipts can contain sensitive personal and business spending information, silent persistence increases privacy and data-exposure risk, especially on shared systems or multi-user environments.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest specifies a concrete naming convention ending in .pdf. The implementation derives the extension from the input file and renames uploads to Vendor_Date_EURAmount plus the original extension, so images or other inputs will not be renamed to a .pdf filename as described.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

Quarterly reporting suggests time-bounded reporting or tax-period aggregation. The summary command simply totals all logged EUR amounts and groups by category, with no quarter calculation, date filtering, or tax-period reporting features.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.