Back to skill

Security audit

accounting assistant

Security checks for vulnerabilities and agentic risk

Overview

This expense-tracking skill is mostly coherent, but it needs Review because its chart code can silently capture and return the user's desktop when image rendering fails.

Review before installing. The ledger behavior is understandable for an expense tracker, but generated reports and exports can contain sensitive financial data, and the chart renderer should be fixed or disabled because it may capture the desktop instead of only the report.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/charts.py:234
Finding

Desktop Screenshot Captured and Returned as a Report Image

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/charts.py:196
Finding

Stored HTML Injection Through an Unescaped Report Label

Content
View full analysis
*{{box-sizing:border-box;margin:0;padding:0}} body{{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;background:#f8f9fa;padding:12px}} .card{{background:white;border-radius:16px;padding:18px;margin-bottom:12px;box-shadow:0 2px 12px rgba(0,0,0,.08)}} .row{{display:flex;flex-wrap:wrap;gap:12px;justify-content:center}} .box{{background:white;border-radius:16px;padding:14px;box-shadow:0 2px 12px rgba(0,0,0,.08);text-align:center;flex:1 1 280px}} .hl{{background:linear-gradient(135deg,#667eea,#764ba2);border-radius:16px;padding:18px;color:white;text-align:center}} table{{width:100%;border-collapse:collapse;margin-top:8px}} th,td{{padding:8px 12px;text-align:left;border-bottom:1px solid #f0f0f0;font-size:13px}} th{{color:#888;font-weight:500}} .ft{{text-align:center;font-size:11px;color:#ccc;margin-top:10px}}
{period_label}
``` The value originates in command input and is persisted to a report: ```python if cmd == "report": report = args.get("report", {}) period = args.get("period_label", "支出报表") html = build_html(report, period, lang) path = CHART_DIR / f"report_{ts}.html" path.write_text(html, encoding='utf-8') ``` ### Technical Analysis The `period_label` field is accepted from command-line JSON and inserted into an HTML document without contextual output encoding. An attacker can therefore close the existing element and inject arbitrary HTML. Because the generated document is written to disk, the issue ...[truncated 1527 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/export.py:91
Finding

CSV Formula Injection in Exported Expense Records

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (15)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger description is extremely broad, matching common spending-related words and symbols that can appear in ordinary conversation. This can cause the skill to activate unexpectedly and persist sensitive financial data without sufficiently explicit user intent, creating privacy and integrity risks.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill reveals a local storage path, but does not clearly warn users up front that their financial records will be written persistently to workspace files. Because the data includes expenses, categories, notes, and member labels, silent persistence raises meaningful privacy and retention concerns.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Telling users to 'just send natural language' makes the boundary between casual discussion and write actions unclear. In a skill that stores persistent ledger entries, this ambiguity increases the chance of accidental data creation, misclassification, or recording of private financial details the user did not intend to save.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The export feature creates shareable copies of sensitive financial data, but the skill does not warn users about the privacy implications of generating CSV or Excel files. Exported files are easier to exfiltrate, mis-share, or leave behind in insecure locations than the primary ledger store.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The title and structure present the taxonomy as a bilingual English/Chinese reference only, which can imply a fixed language/locale expectation for the skill. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern unless the restriction is explicitly justified or alternatives are offered.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The HTML report builder defaults lang to zh, and the main entrypoint also defaults to Chinese via args.get("lang", "zh"), causing the generated report text to be Chinese unless the caller explicitly overrides it. This is a natural-language locale policy issue because the skill forces a specific language by default rather than offering a user choice or clearly documenting a justified locale restriction.

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/charts.py (reported line 223)May include surrounding context.

python
tmp_png = html_path.with_suffix('.png')
    # Try qlmanage first (most reliable on macOS)
    try:
        r = subprocess.run(
            ['qlmanage', '-t', '-s', '900', '-o', str(tmp_png.parent), str(html_path)],
            capture_output=True, timeout=15
        )

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill launches platform tools to process local files without any user-facing disclosure, and one fallback path uses screencapture. In an agent setting, undisclosed OS tool execution can surprise users and, combined with screen capture behavior, increases privacy and trust risk.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

The fallback executes macOS screencapture, which can capture screen contents rather than rendering only the intended chart. If triggered in a real user session, it may unintentionally include other visible windows or sensitive information, creating a privacy leak beyond the chart data itself.

Content

Scanner excerpt · scripts/charts.py (reported line 236)May include surrounding context.

python
pass
    # Fallback: use Safari/webkit
    try:
        r = subprocess.run(
            ['screencapture', '-x', '-t', 'png', str(tmp_png)],
            capture_output=True, timeout=5
        )

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/charts.py (reported line 259)May include surrounding context.

python
tmp_png = tmp_svg.with_suffix('.png')
    tmp_svg.write_text(svg_text, encoding='utf-8')
    try:
        r = subprocess.run(
            ['qlmanage', '-t', '-s', str(size), '-o', str(tmp_png.parent), str(tmp_svg)],
            capture_output=True, timeout=15
        )

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script writes expense reports and chart artifacts to persistent local storage under the user's home directory without warning or retention controls. Because the data contains spending totals, categories, and time-based trends, persistent files may expose sensitive financial information to other local users, backups, or later compromise.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This code writes exported ledger data, including notes, tags, raw input, and timestamps, to files under the user's home directory. While the script's purpose is export, there is no explicit user-facing warning, confirmation, or disclosure in the code that personal financial data will be persisted to disk at a specific path.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The JSON export writes complete entry objects to a file, which may contain sensitive personal finance data. The code does not provide any warning or confirmation about creating a persistent local copy of that data.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The docstring and comment describe export_excel as generating an Excel-compatible CSV by using BOM, but the function calls export_csv({**args, "bom": True}) while export_csv only checks no_bom and ignores bom. If callers pass {"no_bom": true}, the Excel export path will produce a non-BOM file despite the documentation claiming otherwise.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code creates and writes persistent local files containing expense and account data, and similar writes also occur later via save_ledger and action_config. Although the module docstring states it is an expense tracker, there is no explicit user-facing disclosure in code comments, prompts, or output that running add/config actions will create or overwrite data under ~/.qclaw/workspace/expense-ledger.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.