Back to skill

Security audit

Convert Spreadsheet Rows

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a local spreadsheet-to-task conversion skill, but its documentation asks for an unspecified API key and overstates capabilities in ways users should review before installing.

Review this skill before installing. It does not show malware-like behavior, but do not provide any API key unless the publisher documents the exact service and data flow. Treat Markdown or Jira output from untrusted spreadsheets as potentially manipulated, and prefer JSON output or inspect generated output before importing it elsewhere.

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/parse.py:25
Finding

Unescaped Spreadsheet Values Permit Markdown and Jira Content Injection

Content
View full analysis

Vulnerability Details

File Location: scripts/parse.py, lines 25–54
Vulnerability Type: Output markup injection caused by missing context-specific escaping
Risk Level: Medium

Vulnerable Code

python
def to_markdown(rows):
    lines = []
    for i, row in rows:
        lines.append(f"| {i} | {row.get('summary', row.get('title', ''))} | {row.get('description', '')} | {row.get('status', 'todo')} | {row.get('priority', 'medium')} |")
    return TEMPLATE_MARKDOWN.format(rows="\n".join(lines))

def to_json(rows):
    tasks = []
    for i, row in rows:
        tasks.append({
            "id": i,
            "summary": row.get("summary", row.get("title", "")),
            "description": row.get("description", ""),
            "status": row.get("status", "todo"),
            "priority": row.get("priority", "medium"),
        })
    return json.dumps({"tasks": tasks}, indent=2, ensure_ascii=False)

def to_jira(rows):
    lines = []
    for i, row in rows:
        lines.append(f"* [{row.get('status', 'todo').upper()}] {row.get('summary', row.get('title', ''))}")
        desc = row.get("description", "")
        if desc:
            lines.append(f"  #description {desc}")
        pri = row.get("priority", "medium")
        lines.append(f"  #priority {pri}")
        lines.append("")
    return "\n".join(lines)

Technical Analysis

The Markdown and Jira conversion functions directly interpolate attacker-controlled CSV fields into syntax-bearing output. No context-specific escaping or newline normalization is applied to summary, title, description, status, or priority.

In Markdown output, values containing pipe characters or line breaks can terminate the intended table cell or create additional rows and document structures. Values may also introduce links, headings, mentions, images, or other misleading rendered content.

In Jira-like output, embedded line breaks and directive-style text can escape the intended field context and int ...[truncated 1850 chars]

Remediation
View remediation

Remediation Suggestions

  1. Implement separate escaping functions for each output format rather than applying a generic sanitizer.
  2. For Markdown table cells:
    • Escape backslashes and pipe characters.
    • Normalize carriage returns and line feeds to safe text or HTML line breaks.
    • Ensure a field cannot create additional rows or block-level Markdown.
  3. For Jira output:
    • Escape or encode syntax-significant characters according to the exact target Jira format.
    • Reject or normalize embedded line breaks where fields are expected to occupy one directive line.
    • Prefer an official Jira API or structured serializer instead of constructing directive-like text manually.
  4. Validate generated output with an appropriate target-format parser before writing or returning it.
  5. Add strict limits for field lengths and row counts to reduce downstream rendering and resource-abuse risks.
  6. Add adversarial tests for pipe characters, CR/LF sequences, backslashes, links, headings, mentions, and directive-like strings.
  7. Document whether sanitization is intended to preserve literal text or reject unsupported syntax, and report any transformation to the user.

Example hardening pattern for Markdown cells:

python
def escape_markdown_cell(value):
    value = "" if value is None else str(value)
    return (
        value.replace("\\", "\\\\")
             .replace("|", "\\|")
             .replace("\r\n", "<br>")
             .replace("\r", "<br>")
             .replace("\n", "<br>")
    )

A distinct Jira-specific escaping function should be used for Jira output.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

There is a clear mismatch between the declared purpose and the actual code behavior. The description claims a data transformation skill for spreadsheet rows into structured task objects, but the code chunk only implements automated tests for skill packaging quality and documentation standards. Its primary function is linting/validation of skill metadata and repository structure, not spreadsheet processing or task conversion. No code in the chunk reads spreadsheet rows, maps fields to Jira tasks, or emits Markdown/JSON outputs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The instruction 'Keep SKILL.md body in English' enforces a specific language in natural-language project policy. The file does not present this as an opt-in choice or provide a clear region/compliance justification, so it matches the language-policy violation criterion.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The statement 'SKILL.md body must be in English; reference docs in English' is a natural-language policy that mandates a specific language. Because no alternative is offered and no justification is provided, this is a policy violation under the locale/language rule.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The README says "When triggered: [trigger condition]" without defining any actual trigger phrase, scope, or exclusion conditions. In a markdown skill description, this creates an ambiguous activation condition that could lead to unintended or inconsistent invocation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The usage section includes a --mode write command with an input file, which suggests the skill may perform write operations or otherwise alter user data. The README provides no user warning, confirmation note, or disclosure about possible data modification or irreversible effects.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest says the skill converts spreadsheet rows into structured Jira task objects in Markdown or JSON formats, which does not inherently require external service credentials. Declaring an API_KEY for "the service" introduces a capability dependency that is unjustified by the documented purpose and hints at external service access outside the conversion scope.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

该行写为“触发条件:[trigger condition]。”,属于未填写的占位描述,没有说明技能在什么具体用户表达下会触发,也没有说明不应触发的情形。对于 README 这类 markdown 文件,这会导致触发范围不清晰,增加误调用风险。

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README advertises read/write execution modes for a skill described as a spreadsheet-row conversion utility, creating a capability mismatch. In agent ecosystems, misleading operational modes can cause users or orchestrators to invoke the skill with broader file-access expectations than intended, increasing the risk of unintended data access or modification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Documenting a write mode without warning about file or data modification effects can mislead users into performing state-changing actions they do not expect. In an agent setting, lack of side-effect disclosure weakens consent and review controls, especially when a command accepts input paths and implies output mutation.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

Requiring an API key for a supposedly local conversion skill is suspicious because it implies undisclosed external service access or credential collection. Even if benign, this mismatch can lead users to expose secrets unnecessarily and obscures the true trust boundary of the skill.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The activation description is broad enough that an agent could invoke this skill on loosely related inputs, causing unintended data transformation or handling of sensitive spreadsheet contents without clear user intent. In an automated agent environment, ambiguous triggering increases the chance of overreach, especially when the skill is framed to parse many formats and process large inputs.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The docstring at L2-L5 and argument help at L57 explicitly state the script accepts Excel files, but the code path in parse_rows only opens the file as CSV and feeds it to csv.DictReader. This is an active contradiction between stated intent in documentation and actual behavior.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The module docstring says it will parse CSV/Excel rows, and the CLI help at L57 also advertises a 'CSV or Excel file path'. However, the implementation uses csv.DictReader on a plain file handle and contains no Excel parsing logic, so .xlsx/.xls inputs are not actually supported.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This Python file contains a natural-language policy constraint in code by requiring README_zh.md to exist. That effectively imposes a specific locale/language requirement on the skill package, but the file does not indicate that this is optional, user-selected, or justified as a region-specific requirement.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The skill is described as converting spreadsheet rows into structured task objects, but the documented CLI examples introduce generic "read" and "write" modes without explaining how they relate to conversion. This documentation suggests broader file-operation behavior than the stated intent and can mislead users about the skill's actual scope.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.