Back to skill

Security audit

XPR Structured Data

Security checks for vulnerabilities and agentic risk

Overview

This skill coherently provides CSV conversion and SVG chart tools, but exported CSVs and custom SVG colors need care when handling untrusted input.

Install is reasonable for local CSV and chart tasks. Avoid feeding attacker-controlled color values into chart generation, and treat generated SVG as untrusted unless rendered through a safe image pipeline. If exporting data that may be opened in Excel or similar tools, neutralize formula-like values first or avoid opening untrusted CSVs directly in spreadsheet software.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
src/index.ts:252
Finding
SVG Markup Injection Through Unvalidated Custom Colors<![CDATA[ ## Vulnerability Details **File Location**: `src/index.ts:252`, `src/index.ts:270`, `src/index.ts:322`, `src/index.ts:360`, `src/index.ts:396`, `src/index.ts:432`, and `src/index.ts:573` **Vulnerability Type**: SVG markup injection **Risk Level**: High ### Vulnerable Code ```ts const palette = colors || DEFAULT_COLORS; ``` Caller-controlled palette entries are subsequently interpolated directly into SVG attributes. For example: ```ts const color = colors[s % colors.length]; svg += `<rect x="${x}" y="${y}" width="${barWidth}" height="${barH}" fill="${color}" rx="2"/>`; ``` The same unsafe interpolation pattern is used for chart bars, legends, line paths, points, and pie slices: ```ts const color = colors[s % colors.length]; svg += `<path d="${pathD}" fill="none" stroke="${color}" stroke-width="2.5" stroke-linejoin="round"/>`; ``` ```ts const color = colors[i % colors.length]; svg += `<path d="M${cx},${cy} L${x1.toFixed(2)},${y1.toFixed(2)} A${radius},${radius} 0 ${largeArc},1 ${x2.toFixed(2)},${y2.toFixed(2)} Z" fill="${color}" stroke="white" stroke-width="2"/>`; ``` ### Technical Analysis The `generate_chart` tool accepts a caller-controlled `colors` array but performs no validation or XML attribute escaping before inserting each color into `fill` or `stroke` attributes. Because the value is placed inside a double-quoted SVG attribute, an attacker can supply quotation marks and SVG markup that terminate the existing attribute or element and introduce additional elements. A conceptual malicious value can close the `fill` attribute and inject an active SVG element such as a script or event-bearing element. The existing `escapeXml` function is applied to chart titles, labels, and series names, but it is not applied to color values. Generic XML escaping would prevent attribute breakout, while strict color validation would additionally prevent unintended CSS or SVG constructs. The tool returns both raw SVG and a base64 SVG data URI. Rendering be ...[truncated 1560 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate every custom color against a strict allowlist before chart generation. If only hexadecimal colors are required, accept formats such as: ```ts const HEX_COLOR = /^#[0-9a-fA-F]{6}(?:[0-9a-fA-F]{2})?$/; function validateColors(colors: unknown): string[] { if (colors === undefined) return DEFAULT_COLORS; if (!Array.isArray(colors) || colors.length === 0) { throw new Error('colors must be a non-empty array'); } return colors.map(color => { if (typeof color !== 'string' || !HEX_COLOR.test(color)) { throw new Error('Each color must be a valid hexadecimal color'); } return color; }); } ``` 2. Use the validated palette in the handler: ```ts const palette = validateColors(colors); ``` 3. XML-escape every value inserted into an SVG attribute, even after semantic validation: ```ts const color = escapeXml(colors[s % colors.length]); ``` 4. Reject empty color arrays, which otherwise produce undefined palette entries. 5. Sanitize generated SVG using a well-maintained SVG sanitizer before rendering it in a browser. 6. Prefer rendering untrusted SVG through a non-scriptable image pipeline. If inline SVG is necessary, enforce a restrictive Content Security Policy and do not permit scripts, external resources, or event-handler attributes. 7. Add regression tests using color values containing `"`, `'`, `<`, `>`, event handlers, and SVG tags, and assert that these inputs are rejected rather than included in the output. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/index.ts:135
Finding
Spreadsheet Formula Injection in JSON-to-CSV Export<![CDATA[ ## Vulnerability Details **File Location**: `src/index.ts:135-145` and `src/index.ts:171-180` **Vulnerability Type**: CSV/spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```ts function escapeCSVField(value: string, delimiter: string): string { if ( value.includes(delimiter) || value.includes('"') || value.includes('\n') || value.includes('\r') ) { return '"' + value.replace(/"/g, '""') + '"'; } return value; } ``` The export routine applies only syntactic CSV escaping: ```ts // Header row lines.push(columns.map(c => escapeCSVField(c, delimiter)).join(delimiter)); // Data rows for (const row of data) { const fields = columns.map(col => { const val = row[col]; if (val === null || val === undefined) return ''; if (typeof val === 'object') return escapeCSVField(JSON.stringify(val), delimiter); return escapeCSVField(String(val), delimiter); }); lines.push(fields.join(delimiter)); } ``` ### Technical Analysis `escapeCSVField` correctly handles CSV delimiters, double quotes, and line breaks, but CSV syntax escaping is not equivalent to spreadsheet formula neutralization. Spreadsheet programs may interpret cells beginning with formula-triggering characters such as `=`, `+`, `-`, or `@` as executable formulas. Quoting such a value according to CSV syntax does not reliably force spreadsheet applications to treat it as plain text. Formula indicators may also be effective after leading spaces, tabs, carriage returns, or other control characters, depending on the spreadsheet program. Both data values and caller-supplied column names pass through `escapeCSVField` without formula neutralization. Consequently, untrusted JSON values or column names can remain active when the generated CSV is opened in spreadsheet software. ### Attack Path 1. An attacker controls or influences a JSON property value or column name passed to `json_to_csv`. 2. The attacker supplies a string beginning with ...[truncated 1327 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a spreadsheet-safe export mode that neutralizes cells beginning with formula markers, including values with leading whitespace or control characters. 2. Prefix dangerous values with an apostrophe or another spreadsheet-compatible text marker. For example: ```ts function neutralizeSpreadsheetFormula(value: string): string { const normalized = value.replace(/^[\u0000-\u0020]+/, ''); if (/^[=+\-@]/.test(normalized)) { return `'${value}`; } return value; } function escapeCSVField(value: string, delimiter: string): string { const safeValue = neutralizeSpreadsheetFormula(value); if ( safeValue.includes(delimiter) || safeValue.includes('"') || safeValue.includes('\n') || safeValue.includes('\r') ) { return '"' + safeValue.replace(/"/g, '""') + '"'; } return safeValue; } ``` 3. Apply the same protection to header names as well as data cells. 4. If exact raw CSV preservation is required, expose a clearly documented option such as `spreadsheetSafe: true`, and make the safe behavior the default for files intended to be opened in spreadsheet applications. 5. Document that ordinary CSV quoting does not prevent formula execution. 6. Add regression tests for values beginning with `=`, `+`, `-`, and `@`, as well as variants preceded by spaces, tabs, carriage returns, and other relevant control characters. 7. Where practical, use a non-executable delivery format for untrusted tabular data or configure spreadsheet import workflows to treat every field as text. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (1)

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The json_to_csv tool exports untrusted string values directly into CSV cells without guarding against spreadsheet formula interpretation. If a field begins with characters such as '=', '+', '-', or '@', opening the generated CSV in Excel or similar software can execute formulas, enabling data exfiltration, misleading content, or command execution chains depending on the client environment.