Back to skill

Security audit

Data Visualization Studio

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a normal data-visualization helper, but its packaged script accepts user-supplied data paths in a way that can trigger undisclosed network retrieval.

Review this skill before installing in environments with access to internal network services or sensitive local files. Use only trusted local data sources and controlled output paths, and consider patching the loader to reject remote URLs and constrain file locations before broader use.

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/visualize_data.py:62
Finding

Unrestricted Remote Data Retrieval Enables Server-Side Request Forgery

Content
View full analysis

Vulnerability Details

File Location: scripts/visualize_data.py, lines 62–70
Vulnerability Type: Server-Side Request Forgery (SSRF) through unrestricted data-source handling
Risk Level: Medium

Vulnerable Code

python
def load_data(data_source: str) -> pd.DataFrame:
    """Load data from various sources."""
    if data_source.startswith('{') or data_source.startswith('['):
        # JSON string
        data = json.loads(data_source)
        return pd.DataFrame(data)
    elif data_source.endswith('.csv'):
        return pd.read_csv(data_source)
    elif data_source.endswith('.json'):
        return pd.read_json(data_source)

Technical Analysis

The data_source parameter is supplied directly to pandas.read_json() after only verifying that the string ends with .json. This suffix check does not establish that the input identifies a local file.

pandas.read_json() accepts URL-like inputs in addition to local paths. Consequently, an attacker who controls data_source can provide an HTTP or HTTPS URL ending in .json. The process may then initiate an outbound request from the environment in which the Skill is running.

This behavior conflicts with the documented interface, which describes data_source as a data-file path or inline JSON string and does not disclose unrestricted network retrieval. The absence of validation for URI schemes, destination hosts, resolved IP addresses, ports, redirects, and response sizes makes the operation vulnerable to SSRF when exposed to untrusted input.

Attack Path

  1. An attacker supplies a URL such as http://internal-service.example/status.json as data_source.
  2. The URL is not inline JSON and passes the .json suffix check.
  3. The application invokes pd.read_json(data_source) without validating the destination.
  4. Pandas retrieves the resource using the network permissions of the Skill process.
  5. If the response contains compati ...[truncated 1189 chars]
Remediation
View remediation

Remediation Suggestions

  1. Treat data_source as a local path unless remote retrieval is an explicit product requirement.
  2. Parse the input as a URI and reject all non-local schemes, including http, https, ftp, and file.
  3. Resolve local paths with pathlib.Path.resolve() and require them to remain within a dedicated, approved input directory.
  4. Reject traversal attempts, symbolic-link escapes, unsupported extensions, and non-regular files.
  5. If remote sources are required:
    • Allowlist permitted schemes, hostnames, ports, and URL paths.
    • Resolve hostnames and block loopback, private, link-local, multicast, reserved, and cloud metadata addresses.
    • Repeat destination validation after DNS resolution and for every redirect.
    • Disable redirects where possible.
    • Enforce connection, read, and total-operation timeouts.
    • Limit response size and validate the response content type before parsing.
    • Route requests through a restricted outbound proxy.
  6. Fetch approved remote content through a hardened HTTP client and pass validated local content to Pandas rather than allowing Pandas to retrieve arbitrary URLs directly.
  7. Add tests covering internal addresses, alternate IP representations, DNS rebinding, redirects, malformed URLs, oversized responses, and path traversal.
Vulnerability Patterns
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The code generally aligns with a visualization tool, so the primary purpose is consistent. However, the declared description overstates functionality. The implementation supports only a small fixed set of chart types and does not implement dashboards. It also does not demonstrate broad statistical plotting beyond histogram and correlation heatmap. Multiple output formats are only partially supported implicitly through Plotly's write_image/write_html rather than explicit handling, though this alone is not the main issue. There are no obvious undeclared sensitive capabilities or permission mismatches; the mismatch is that the description materially overclaims the breadth of visualization features compared with the actual code.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.