Back to skill

Security audit

Phy Openapi Mock Server

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent local API mock-server helper, but it uses unsafe command snippets and unpinned downloaded tooling that deserve review before installation.

Review this skill before installing. Use only trusted OpenAPI specs and filenames, prefer pinned Prism or Mockoon versions installed locally with a lockfile, avoid global npm installs when possible, and keep the mock server bound to localhost. Do not include real secrets, production tokens, or sensitive example data in specs served by the mock server.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:91
Finding
User-Controlled Spec Filename Enables Python Code Injection<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 91–103, with repeated unsafe interpolation at lines 151 and 228 **Vulnerability Type**: Python source-code injection through user-controlled filename interpolation **Risk Level**: High ### Vulnerable Code ```bash if [[ "$SPEC_FILE" == *.yaml ]] || [[ "$SPEC_FILE" == *.yml ]]; then python3 -c "import yaml,sys; yaml.safe_load(open('$SPEC_FILE'))" 2>&1 && echo "✅ YAML syntax valid" || echo "❌ YAML syntax error" elif [[ "$SPEC_FILE" == *.json ]]; then python3 -c "import json,sys; json.load(open('$SPEC_FILE'))" 2>&1 && echo "✅ JSON syntax valid" || echo "❌ JSON syntax error" fi python3 -c " import yaml, json, sys try: with open('$SPEC_FILE') as f: spec = yaml.safe_load(f) if '$SPEC_FILE'.endswith(('.yaml','.yml')) else json.load(f) ``` The same unsafe construction is repeated when generating endpoint inventories and test commands: ```bash python3 -c " import yaml, json, sys spec_file = '$SPEC_FILE' with open(spec_file) as f: ``` ```bash python3 -c " import yaml, json spec_file = '$SPEC_FILE' with open(spec_file) as f: ``` ### Technical Analysis The user-provided `SPEC_FILE` value is interpolated directly into Python source passed to `python3 -c`. Shell quoting does not make the resulting Python string safe. A filename containing a single quote can terminate the Python string literal and introduce additional Python statements. Because Python provides direct access to operating-system functionality, successful injection can invoke commands, read files, alter project content, or perform network operations with the privileges of the user running the Skill. This exceeds the minimum privileges needed to parse an OpenAPI document. The file path should be treated strictly as data and passed through an argument or environment variable rather than incorporated into executable source. ### Attack Path 1. An attacker creates or supplies an OpenAPI file with a specially crafted fi ...[truncated 1054 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Pass the path as a positional argument instead of interpolating it into Python source: ```bash python3 -c ' import sys import yaml with open(sys.argv[1], encoding="utf-8") as file: yaml.safe_load(file) ' "$SPEC_FILE" ``` For logic supporting both JSON and YAML: ```bash python3 - "$SPEC_FILE" <<'PY' import json import sys import yaml spec_file = sys.argv[1] with open(spec_file, encoding="utf-8") as file: if spec_file.lower().endswith((".yaml", ".yml")): spec = yaml.safe_load(file) else: spec = json.load(file) PY ``` Apply this argument-based pattern to every embedded Python block, including lines 91, 93, 100, 151, and 228. Additional hardening should include: - Rejecting filenames containing NUL characters or unsupported extensions. - Resolving and validating the path before opening it. - Distinguishing local file input from URL input explicitly. - Avoiding dynamic source construction for all user-controlled values. - Adding regression tests using filenames containing quotes, spaces, newlines, and shell metacharacters. ]]>

T08 · Insecure Dependencies

Error
Location
SKILL.md:120
Finding
Mutable and Unpinned Third-Party Packages Are Downloaded and Executed<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 120–138 and 430 **Vulnerability Type**: Unpinned runtime dependencies and mutable container images **Risk Level**: High ### Vulnerable Code ```bash elif npx --yes @stoplight/prism-cli@latest --version &>/dev/null 2>&1; then echo "✅ Prism available via npx" else echo "Installing Prism..." npm install -g @stoplight/prism-cli # Or: yarn global add @stoplight/prism-cli # Or: npx -p @stoplight/prism-cli prism (no install needed) fi ``` ```bash docker run --rm -p 4010:4010 \ -v "$(pwd):/tmp/spec" \ stoplight/prism:latest \ mock /tmp/spec/openapi.yaml -h 0.0.0.0 ``` ```bash npm install -g @mockoon/cli ``` ### Technical Analysis The Skill downloads and executes third-party code without pinning immutable versions: - `@stoplight/prism-cli@latest` explicitly selects a mutable release. - `npm install -g @stoplight/prism-cli` and `npm install -g @mockoon/cli` resolve whichever versions are current at execution time. - `stoplight/prism:latest` is a mutable container tag rather than a verified image digest. - `npx --yes` suppresses confirmation before downloaded package code is executed. - Global installation modifies the user's persistent tool environment even though a project-local or ephemeral installation would be sufficient. Consequently, the code reviewed during the Skill audit may differ from the code eventually downloaded and run. A compromised publisher account, registry, release, transitive dependency, or mutable container tag could introduce arbitrary executable behavior. ### Attack Path 1. An upstream package, transitive dependency, registry account, or container image is compromised or publishes an unsafe update. 2. The Skill invokes `npx`, `npm install -g`, or `docker run` using an unpinned name or mutable `latest` tag. 3. The package registry or container registry supplies the changed artifact. 4. Package lifecycle scripts, CLI initialization code, or container entr ...[truncated 792 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin npm tools to explicitly reviewed versions, for example: ```bash npx --yes @stoplight/prism-cli@<reviewed-version> --version npx --yes @stoplight/prism-cli@<reviewed-version> mock ... ``` - Use a project-local `package.json` and lockfile with integrity metadata instead of global installation. - Run `npm ci` against a committed lockfile when installation is necessary. - Disable lifecycle scripts where compatible: ```bash npm ci --ignore-scripts ``` - Verify that disabling scripts does not break the selected package before adopting this control. - Pin the Docker image by immutable digest: ```bash docker run --rm \ -p 127.0.0.1:4010:4010 \ -v "$(pwd):/tmp/spec:ro" \ stoplight/prism@sha256:<reviewed-digest> \ mock /tmp/spec/openapi.yaml -h 0.0.0.0 ``` - Mark the specification mount read-only unless write access is explicitly required. - Avoid global package installations for a temporary mock-server task. - Establish a dependency-update review process and scan both direct and transitive dependencies before changing pinned versions. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:135
Finding
Docker Fallback Publishes the Mock Server on All Host Interfaces<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 135–138 **Vulnerability Type**: Excessive network exposure and insecure service binding **Risk Level**: Medium ### Vulnerable Code ```bash docker run --rm -p 4010:4010 \ -v "$(pwd):/tmp/spec" \ stoplight/prism:latest \ mock /tmp/spec/openapi.yaml -h 0.0.0.0 ``` ### Technical Analysis Docker's `-p 4010:4010` syntax normally publishes the container port on all host interfaces. Prism is also instructed to listen on `0.0.0.0` inside the container. Binding Prism to all container interfaces is necessary for Docker port forwarding, but publishing the host port without a host address exposes it beyond the local machine. This conflicts with the Skill's declared local-development purpose and with its primary non-Docker command, which binds Prism to `127.0.0.1`. The mock server does not enforce authentication by default and may return examples or schema-derived data from the supplied specification. Network-wide exposure is not required to provide a local mock API. ### Attack Path 1. A user follows the documented Docker fallback command on a workstation connected to a shared, corporate, wireless, or otherwise reachable network. 2. Docker publishes TCP port 4010 on all host interfaces. 3. Another network participant discovers or connects to the exposed port. 4. The participant enumerates and invokes mock API routes without authentication. 5. The participant obtains mock responses, validation behavior, API structure, or operational details present in the specification. Actual reachability depends on host firewall and network configuration, but the command itself does not enforce local-only access. ### Impact Assessment A remote network participant may be able to: - Access unauthenticated mock endpoints. - Enumerate API paths and methods through behavior or known specification routes. - View example response data included in the OpenAPI document. - Trigger dynamic response generation and ...[truncated 281 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Restrict Docker's published port to the loopback interface: ```bash docker run --rm \ -p 127.0.0.1:4010:4010 \ -v "$(pwd):/tmp/spec:ro" \ stoplight/prism@sha256:<reviewed-digest> \ mock /tmp/spec/openapi.yaml -h 0.0.0.0 ``` Further hardening should include: - Documenting that the service is intended only for local development. - Making the bind address configurable but defaulting it to loopback. - Requiring explicit confirmation before allowing external network exposure. - Applying host firewall rules when non-local access is genuinely needed. - Avoiding real credentials, production data, or sensitive examples in mock specifications. - Using a read-only bind mount because Prism only needs to read the specification. ]]>
Vulnerability Patterns
  • 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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (19)

External Script Fetching

High
Category
Supply Chain
Content
---

## Step 5: Generate Test curl Commands

After starting, output ready-to-run curl commands for every endpoint:
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
```bash
# List all pets
curl -s -X GET "http://localhost:4010/pets" | python3 -m json.tool

# Get specific pet
curl -s -X GET "http://localhost:4010/pets/1" | python3 -m json.tool
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
curl -s -X GET "http://localhost:4010/pets" | python3 -m json.tool

# Get specific pet
curl -s -X GET "http://localhost:4010/pets/1" | python3 -m json.tool

# Create a pet (replace {} with actual body)
curl -s -X POST "http://localhost:4010/pets" \
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
curl -s -X GET "http://localhost:4010/pets/1" | python3 -m json.tool

# Create a pet (replace {} with actual body)
curl -s -X POST "http://localhost:4010/pets" \
  -H "Content-Type: application/json" \
  -d '{"name": "Buddy", "tag": "dog"}' | python3 -m json.tool
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
-d '{"name": "Buddy", "tag": "dog"}' | python3 -m json.tool

# Test a 404 response
curl -s -X GET "http://localhost:4010/pets/99999" | python3 -m json.tool
# → Prism returns the spec's 'default' response example

# Test validation mode rejection
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
# → Prism returns the spec's 'default' response example

# Test validation mode rejection
curl -s -X POST "http://localhost:4010/pets" \
  -H "Content-Type: application/json" \
  -d '{"invalid_field": true}' | python3 -m json.tool
# → Returns 422 with validation error details
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Credential Access

High
Category
Privilege Escalation
Content
```

```bash
# In your frontend .env.local
NEXT_PUBLIC_API_URL=http://localhost:4010   # Mock during dev
# NEXT_PUBLIC_API_URL=https://api.prod.com  # Uncomment for production
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
MCP server references in the skill manifest without version pinning are a rug-pull risk.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The description frames the skill as local-only, yet the file documents using a spec URL as input and running npx/npm/docker commands that inherently contact external services to retrieve the spec or tooling. That is broader network behavior than the 'only npx and your local spec file' claim suggests.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The listed triggers include phrases like "I need a local API", "frontend needs a backend stub", "mock this endpoint", and "start a mock server," which are broad natural-language requests rather than narrowly scoped invocation commands. Without exclusion conditions or clearer activation constraints, these phrases may overlap with ordinary discussion and trigger the skill unintentionally.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
Lines L75-L76 describe validation of the provided spec, and L80 exempts http inputs from the file-exists check, implying URL support. However, the subsequent Python snippets unconditionally call open('$SPEC_FILE'), which will fail for a URL instead of fetching it, contradicting the documented behavior.

Rp1

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding
The skill runs Prism via `npx ...@latest`, which fetches and executes code from the npm registry at runtime without pinning a specific version. If the upstream package is compromised or a breaking/malicious release is published, users of the skill could execute unreviewed code on their machine.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The alternative command `npx -p @stoplight/prism-cli prism` also downloads and executes an unpinned package from npm. This creates a supply-chain execution path where the exact code run can change over time or be replaced by a malicious release.

Rp1

Medium
Category
MCP Rug Pull
Confidence
88% confidence
Finding
The Docker alternative uses `stoplight/prism:latest`, which is not immutable and may change between runs. That allows unreviewed image contents to be pulled later and undermines reproducibility and trust in the executed container.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The main server start command uses `npx --yes @stoplight/prism-cli mock`, again pulling executable code from npm at runtime without a fixed version. Because this is the primary workflow, it materially increases the chance of executing compromised upstream code.

External Transmission

Medium
Category
Data Exfiltration
Content
---

## Step 5: Generate Test curl Commands

After starting, output ready-to-run curl commands for every endpoint:
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
curl -s -X GET "http://localhost:4010/pets/1" | python3 -m json.tool

# Create a pet (replace {} with actual body)
curl -s -X POST "http://localhost:4010/pets" \
  -H "Content-Type: application/json" \
  -d '{"name": "Buddy", "tag": "dog"}' | python3 -m json.tool
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
curl -s -X GET "http://localhost:4010/pets/1" | python3 -m json.tool

# Create a pet (replace {} with actual body)
curl -s -X POST "http://localhost:4010/pets" \
  -H "Content-Type: application/json" \
  -d '{"name": "Buddy", "tag": "dog"}' | python3 -m json.tool
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
SKILL.md:348