Back to skill

Security audit

Chat Order OCR|聊天訂單整理工具

Security checks for vulnerabilities and agentic risk

Overview

This skill is a local chat-order parsing/OCR helper with disclosed file input, OCR, and output behavior, but users should handle CSV exports and screenshots carefully.

Install only if you are comfortable processing order chats and screenshots locally with Tesseract. Prefer JSON for exact records; if exporting CSV for Excel or similar tools, be aware that crafted chat text could be interpreted as a spreadsheet formula unless sanitized. Review screenshots for sensitive unrelated content before OCR and choose output paths deliberately.

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
scripts/order_ocr_cli.py:169
Finding

Spreadsheet Formula Injection in CSV Exports

Content
View full analysis

Vulnerability Details

File Location: scripts/order_ocr_cli.py, lines 169–173
Vulnerability Type: CSV/spreadsheet formula injection
Risk Level: Medium

Vulnerable Code

python
def write_csv(rows: list[dict[str, object]], stream: io.TextIOBase) -> None:
    writer = csv.writer(stream)
    writer.writerow(["姓名", "原始品項", "對應品項", "數量", "來源", "來源檔案", "對應狀態", "信心"])
    for row in rows:
        writer.writerow([row["person"], row["item"], row["matched_item"], row["qty"], row["source"], row["source_file"], row["match_status"], row["confidence"]])

Technical Analysis

The application exports attacker-controlled chat and OCR values directly into CSV cells. The csv.writer class correctly escapes CSV delimiters and quotation marks, but it does not protect against spreadsheet formulas.

Spreadsheet applications may interpret cells beginning with formula prefixes such as =, +, -, or @ as executable formulas rather than plain text. Leading whitespace or control characters may also be used to conceal these prefixes.

An attacker can provide an order item beginning with a formula expression and ending with a quantity marker required by the parser. For example, an input structurally resembling the following can cause the item field to begin with =:

text
Customer
=1+1 +1

The parsed item is subsequently written to the CSV without formula neutralization. More elaborate spreadsheet formulas may attempt to create misleading hyperlinks, initiate external resource requests, or use application-specific functionality.

This issue applies primarily to fields derived from untrusted input, including person, item, matched_item, and source_file. Catalog values can also become dangerous if an untrusted catalog is supplied.

Attack Path

  1. An attacker submits crafted chat or OCR content containing an order item whose first significant character is a spreadsheet formula prefix.
  2. `pa ...[truncated 1248 chars]
Remediation
View remediation

Remediation Suggestions

Sanitize every string written to CSV when it may originate from chat text, OCR output, file paths, or user-supplied catalogs.

  1. Detect formula prefixes after removing or accounting for leading whitespace and control characters.
  2. Prefix dangerous values with a single quote so spreadsheet applications treat them as text.
  3. Apply protection to every exported textual field rather than only person and item.
  4. Preserve the original value separately in JSON if exact, unsanitized data is required for programmatic processing.
  5. Document that CSV output is spreadsheet-safe text rather than a lossless serialization format.
  6. Add regression tests for values beginning with =, +, -, @, tabs, carriage returns, and leading spaces.

Example hardening approach:

python
FORMULA_PREFIXES = ("=", "+", "-", "@")

def safe_csv_cell(value: object) -> object:
    if not isinstance(value, str):
        return value

    candidate = value.lstrip(" \t\r\n")
    if candidate.startswith(FORMULA_PREFIXES):
        return "'" + value
    return value

def write_csv(rows: list[dict[str, object]], stream: io.TextIOBase) -> None:
    writer = csv.writer(stream)
    writer.writerow(["姓名", "原始品項", "對應品項", "數量", "來源", "來源檔案", "對應狀態", "信心"])
    for row in rows:
        values = [
            row["person"],
            row["item"],
            row["matched_item"],
            row["qty"],
            row["source"],
            row["source_file"],
            row["match_status"],
            row["confidence"],
        ]
        writer.writerow([safe_csv_cell(value) for value in values])
Vulnerability Patterns
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (10)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The entire skill description is written only in Traditional Chinese and does not indicate that users may choose another language or that the skill is intentionally limited to a Chinese-speaking context. Under the stated policy, forcing a specific language without opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill documents use of local file I/O and shell execution via a Python CLI, but it does not declare any explicit tool scope such as allowed tools or permissions. This creates an authorization gap: an agent may be induced to read/write arbitrary local files or invoke shell commands beyond what a reviewer or runtime policy expects.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The instructions tell the user to ensure Tesseract has chi_tra+eng language data, which imposes a specific language/locale configuration. The file does not offer an opt-in choice for other OCR languages or explain that the skill is intentionally limited to Traditional Chinese contexts.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The parameter table prescribes --ocr-lang chi_tra+eng as the OCR language setting, which enforces a specific locale expectation. There is no accompanying language choice, opt-in, or explicit statement that this is a region-specific skill.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

Line L73 says 'CLI 本身不會讀取圖片', directly contradicting earlier documentation at L12, L14, L31, L39, and L53 stating the CLI accepts --images/--images-dir and performs OCR on image files with Tesseract. This is an active contradiction in the skill's own documentation about a core capability.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
78% confidence
Finding

The batch OCR examples operate on screenshots and image directories, which may contain sensitive personal or order information, yet the markdown provides no warning about reviewing file contents before processing. For markdown files, SQP-2 covers omitted warnings about behaviors that could affect user privacy.

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 · scripts/order_ocr_cli.py (reported line 132)May include surrounding context.

python
def ocr_image(path: Path, lang: str, psm: int) -> str:
    command = ["tesseract", str(path), "stdout", "-l", lang, "--psm", str(psm)]
    completed = subprocess.run(command, check=True, capture_output=True, text=True, encoding="utf-8", errors="replace")
    return completed.stdout.strip()

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 · scripts/test_order_ocr_cli.py (reported line 17)May include surrounding context.

python
def run(*args: str) -> dict:
    result = subprocess.run([sys.executable, str(CLI), *args], check=True, capture_output=True, text=True)
    return json.loads(result.stdout)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The HTML declares Traditional Chinese as the page language and the footer states the tool organizes and explains content in Traditional Chinese. This is a natural-language locale constraint presented without opt-in, fallback, or justification that the skill is region-specific, which fits the language/locale policy-violation category.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown file includes CLI examples that write results to local files via --output, but it does not warn users that running the commands will create or overwrite files on disk. Because SQP-2 applies to markdown files when behaviors may affect user data or system integrity, a brief warning about output-file side effects is warranted.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.