Back to skill

Security audit

Expanso json-to-csv

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent JSON-to-CSV skill, but its server mode is exposed too broadly by default and its CSV output can be unsafe for spreadsheet use with untrusted data.

Review before installing. Use CLI mode or bind the MCP server to 127.0.0.1/firewall it if possible, do not expose the port to untrusted networks, and treat CSV generated from untrusted JSON as unsafe to open directly in spreadsheets unless formula neutralization and complete CSV escaping are 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 (3)

T09 · Insecure Skill Coding Practices

Warning
Location
pipeline-mcp.yaml:12
Finding

Unauthenticated HTTP Service Exposed on All Network Interfaces

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
pipeline-cli.yaml:29
Finding

Spreadsheet Formula Injection in Generated CSV Values

Content
View full analysis
$columns.map_each(col -> if obj.get(col).or("").string().contains($delimiter) || obj.get(col).or("").string().contains("\"") { "\"" + obj.get(col).or("").string().re_replace_all("\"", "\"\"") + "\"" } else { obj.get(col).or("").string() }).join($delimiter)) root.csv = $header + "\n" + $rows.join("\n") ``` The MCP pipeline contains the same vulnerable conversion behavior: ```yaml let header = $columns.join($delimiter) let rows = $data.map_each(obj -> $columns.map_each(col -> if obj.get(col).or("").string().contains($delimiter) || obj.get(col).or("").string().contains("\"") { "\"" + obj.get(col).or("").string().re_replace_all("\"", "\"\"") + "\"" } else { obj.get(col).or("").string() }).join($delimiter)) root.csv = $header + "\n" + $rows.join("\n") ``` ### Technical Analysis The converter emits values beginning with spreadsheet formula indicators such as `=`, `+`, `-`, or `@` without neutralization. Quoting a CSV field is not a reliable defense because spreadsheet applications can still interpret quoted CSV cells as formulas. Consequently, an attacker who controls JSON values can place formula content into the generated CSV. The risk is realized when a user opens or imports that CSV into spreadsheet software. Depending on the spreadsheet application and its security settings, formulas may initiate external requests, mislead the user, expose spreadsheet data, or invoke dangerous legacy functionality. ### Attack Path 1. An attacker supplies JSON containing a formula-leading value, for example: ```json [{"name":"=HYPERLINK(\"https://attacker.example/\",\"Open report\")","amount":10}] ``` 2. The pipeline converts the value to CSV without neutra ...[truncated 854 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
pipeline-cli.yaml:29
Finding

Incomplete CSV Escaping Permits Row and Column Structure Injection

Content
View full analysis
$columns.map_each(col -> if obj.get(col).or("").string().contains($delimiter) || obj.get(col).or("").string().contains("\"") { "\"" + obj.get(col).or("").string().re_replace_all("\"", "\"\"") + "\"" } else { obj.get(col).or("").string() }).join($delimiter)) root.csv = $header + "\n" + $rows.join("\n") ``` The MCP pipeline uses the same encoding logic: ```yaml let header = $columns.join($delimiter) let rows = $data.map_each(obj -> $columns.map_each(col -> if obj.get(col).or("").string().contains($delimiter) || obj.get(col).or("").string().contains("\"") { "\"" + obj.get(col).or("").string().re_replace_all("\"", "\"\"") + "\"" } else { obj.get(col).or("").string() }).join($delimiter)) root.csv = $header + "\n" + $rows.join("\n") ``` ### Technical Analysis The implementation quotes a value only when it contains the selected delimiter or a double quote. It does not quote fields that contain carriage-return or line-feed characters. Under standard CSV rules, fields containing a delimiter, double quote, carriage return, or line feed must be quoted, with embedded double quotes doubled. Column names are obtained from attacker-controlled object keys and joined directly: ```yaml let header = $columns.join($delimiter) ``` No escaping is applied to headers. A key containing the delimiter, a quote, or a line break can therefore alter the apparent header structure. Likewise, a value containing a newline but no delimiter or quote can produce an unintended CSV record. ### Attack Path 1. An attacker provides JSON with a malicious key or value containing a line break or delimiter. 2. Column discovery accepts the attacker-controlled object key. 3. T ...[truncated 919 chars]
Remediation
View remediation
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 (3)

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

bash
PORT=8080 expanso-edge run pipeline-mcp.yaml &
curl -X POST http://localhost:8080/convert \
  -H "Content-Type: application/json" \
  -d '{"data": [{"name":"Alice","age":30},{"name":"Bob","age":25}]}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · pipeline-mcp.yaml (reported line 6)May include surrounding context.

yaml
#
# Usage:
#   PORT=8080 expanso-edge run pipeline-mcp.yaml &
#   curl -X POST http://localhost:8080/convert \
#     -d '{"data": [{"name":"Alice","age":30}]}'

name: "json-to-csv-mcp"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

This manifest enables an HTTP server bound to 0.0.0.0 and exposes a POST /convert endpoint, which means user-supplied data is received over the network. Although the file is a manifest rather than code, the visible usage/comments do not include any warning that the skill opens a network-accessible service or processes submitted payload data.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.