Back to skill

Security audit

data-audit

Security checks for vulnerabilities and agentic risk

Overview

This is a local data-auditing skill, but it needs Review because its manifest understates write behavior and CSV exports are not hardened against spreadsheet-formula injection.

Review before installing. Use it only on directories you intentionally choose, remember that snapshots and reports may contain file paths, names, hashes, and metadata, and treat ~/.data-audit-logs as retained local history. Avoid opening CSV exports from untrusted directories or untrusted snapshot files in spreadsheet software until formula sanitization is added.

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/auditor.py:466
Finding

CSV Formula Injection Through Untrusted File and Path Metadata

Content
View full analysis

Vulnerability Details

File Location: scripts/auditor.py, lines 466–484
Vulnerability Type: CSV formula injection
Risk Level: Medium

The CSV export function writes file names, paths, and comparison-report fields directly into CSV cells without neutralizing spreadsheet formula prefixes.

Vulnerable Code

python
try:
    with open(output_path, 'w', newline='', encoding='utf-8-sig') as f:
        if data_type == "changes" and "changes" in data:
            writer = csv.DictWriter(f, fieldnames=["type", "file", "size", "size_before", "size_after", "diff_human", "ext"])
            writer.writeheader()
            for row in data["changes"]:
                writer.writerow(row)
            print(f"   📄 对比报告已导出 CSV: {output_path} ({len(data['changes'])} 条)")
        elif data_type == "snapshot" and "files" in data:
            writer = csv.DictWriter(f, fieldnames=["path", "name", "size", "ext", "type", "modified", "hash"])
            writer.writeheader()
            for row in data["files"]:
                writer.writerow(row)
            print(f"   📄 快照已导出 CSV: {output_path} ({len(data['files'])} 文件)")
        elif data_type == "validate" and "issues" in data:
            writer = csv.DictWriter(f, fieldnames=["type", "path"])
            writer.writeheader()
            for row in data["issues"]:
                writer.writerow(row)

Technical Analysis

File names and relative paths originate from the directory being audited. Comparison reports can also contain fields read from user-supplied or externally supplied snapshot JSON files. These values are passed directly to csv.DictWriter.writerow().

CSV quoting only preserves CSV syntax; it does not prevent spreadsheet applications from interpreting cells beginning with formula-triggering characters such as =, +, -, or @. Some spreadsheet clients may also ignore leading whitespace or control characters before evalu ...[truncated 1885 chars]

Remediation
View remediation

Remediation Suggestions

Introduce a centralized CSV-cell sanitization function and apply it to every string field before passing rows to csv.DictWriter.

The sanitizer should:

  1. Detect values whose first meaningful character is =, +, -, or @.
  2. Account for leading whitespace, tabs, carriage returns, newlines, and other control characters that spreadsheet clients may ignore.
  3. Prefix dangerous values with an apostrophe or use another neutralization method verified against supported spreadsheet applications.
  4. Preserve unmodified values in JSON output when exact forensic fidelity is required, while treating CSV as a presentation format requiring sanitization.
  5. Sanitize all externally influenced fields, including path, name, file, type, ext, and textual fields loaded from snapshot files.

Example hardening pattern:

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

def sanitize_csv_cell(value):
    if not isinstance(value, str):
        return value

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

def sanitize_csv_row(row):
    return {
        key: sanitize_csv_cell(value)
        for key, value in row.items()
    }

Each export loop should then use:

python
for row in data["files"]:
    writer.writerow(sanitize_csv_row(row))

Apply the same treatment to comparison changes and validation issues. Add regression tests using malicious file names and crafted snapshot fields beginning with each formula prefix, including variants preceded by whitespace or control characters.

Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

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

python
LOG_FILE = LOG_DIR / "audit_history.json"
VERSION = "1.1.0"
EXTS_TEXT = {'.txt', '.csv', '.json', '.xml', '.yaml', '.yml', '.md', '.log',
             '.html', '.js', '.py', '.sh', '.conf', '.cfg', '.ini', '.env'}
EXTS_BINARY = {'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.pdf', '.doc', '.docx',
               '.xls', '.xlsx', '.zip', '.gz', '.tar', '.db', '.sqlite', '.bin'}
EXTS_HIDDEN = {'.pyc', '.o', '.so', '.dylib', '.DS_Store'}

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

md
|----------|---------|-------|--------|---------|------------|
| `--snapshot` | 目录快照 | Path | stdout/JSON/CSV | No | Read only |
| `--compare` | 快照对比 | JSON files | stdout/JSON/CSV | No | Read only |
| `--log` | 操作记录 | Action text | Log file | No | Write ~/.data-audit-logs |
| `--history` | 历史查询 | None | stdout | No | Read ~/.data-audit-logs |
| `--validate` | 健康检查 | Path | stdout/JSON/CSV | No | Read only |

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

md
- ❌ No dynamic imports from external sources
- ❌ No system commands via subprocess/shell
- ❌ No telemetry, analytics, or usage reporting
- ❌ No modification of user files (logs only write to ~/.data-audit-logs)

### Data Privacy
- All processing is local — no data leaves the machine

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill performs filesystem reads and writes but does not declare an explicit tool scope such as permissions or allowed-tools. This creates an authorization ambiguity where the agent may invoke the skill without clear operator visibility into its file access, increasing the chance of unintended data exposure or writes.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The skill description and invocation guidance are presented as Chinese-only user-facing instructions, with no indication that users may choose another language. This can violate language/locale policy when a skill implicitly constrains interaction language without opt-in or documented justification.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger keywords are very broad, covering generic terms like integrity checking, governance, and change tracking without tight activation rules. Over-broad invocation can cause the skill to run in contexts the user did not intend, leading to unnecessary directory scanning, hashing of sensitive files, or persistent logging.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
92% confidence
Finding

The skill persists operation history in ~/.data-audit-logs, creating cross-session state that may contain sensitive action text and target paths. Persistent local logs can reveal directory structures, business operations, or audit activity to other local users, later sessions, or unrelated workflows if not tightly controlled.

Content

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

md
|----------|---------|-------|--------|---------|------------|
| `--snapshot` | 目录快照 | Path | stdout/JSON | No | Read only |
| `--compare` | 快照对比 | JSON files | stdout/JSON | No | Read only |
| `--log` | 操作记录 | Action text | Log file | No | Write ~/.data-audit-logs |
| `--history` | 历史查询 | None | stdout | No | Read ~/.data-audit-logs |
| `--validate` | 健康检查 | Path | stdout/JSON | No | Read only |

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The documentation explicitly allows writes to ~/.data-audit-logs while claiming no modification of user files beyond logs, but those logs are still persistent user-file modifications. This persistence increases privacy and data-retention risk because operational metadata can accumulate and be accessed outside the immediate task context.

Content

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

md
- ❌ No dynamic imports from external sources
- ❌ No system commands via subprocess/shell
- ❌ No telemetry, analytics, or usage reporting
- ❌ No modification of user files (logs only write to ~/.data-audit-logs)

### Data Privacy
- All processing is local — no data leaves the machine

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This manifest uses Chinese for the primary description and several keywords, but does not indicate that the skill is region-specific or provide any user opt-in for language/locale. Under the policy, forcing a specific language without choice or justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Scope Creep

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The declared read-only sandbox conflicts directly with the listed capability filesystem-write-log. Even without code execution, this is a security-relevant integrity issue because deployment systems or operators may grant trust based on the read-only claim while the skill expects write access, creating a permission-model mismatch and audit blind spots.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest makes contradictory security claims: it declares a read-only sandbox while also advertising file-writing capability and commands that generate logs or reports. This can mislead reviewers, policy engines, or users about the actual write behavior of the skill, weakening trust boundaries and potentially allowing unexpected filesystem modification in environments that rely on manifest metadata.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains natural-language descriptions, help text, and examples only in Chinese. Under the policy, forcing a specific language without user opt-in is a locale/language policy violation unless the restriction is explicitly justified, which is not present here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The file presents the skill documentation entirely in Chinese, starting with the title '更新日志', with no indication that language selection is optional or that the skill is intentionally region-specific. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The comment states '纯Python标准库,无外部依赖', which imposes Chinese-language wording in the file without any indication that language choice is configurable or intentionally limited to a Chinese-only context. This can violate the language/locale policy when no user opt-in or justification is provided.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest highlights 'JSON 报告导出' as the export capability, while the implementation explicitly supports '--export-csv' and writes snapshot, compare, and validation results as CSV. This is a mild description-behavior mismatch because CSV export is additional behavior not reflected in the stated manifest capabilities.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The stated purpose is snapshotting, comparing, logging, and validating data directories for audit/compliance use. The '--init-config' path writes a default config file anywhere on disk, which is auxiliary tooling behavior not described in the manifest's scope.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.