Back to skill

Security audit

PixelDojo

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims for PixelDojo media generation, but it needs Review because its helpers can send the API key to an unrestricted API-base override and download unvalidated service-provided URLs to local disk.

Install only if you trust the PixelDojo service and the environment that launches the helper scripts. Do not set PIXELDOJO_API_BASE except for a trusted HTTPS PixelDojo-compatible endpoint, avoid submitting confidential prompts or private image URLs, and choose output paths deliberately because generated files are saved persistently.

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

Warning
Location
generate.sh:11
Finding

Unvalidated API Base Override Can Disclose Bearer Credentials

Content
View full analysis

Vulnerability Details

File Location: generate.sh:11,98-101; models.sh:6-14; status.sh:7,22-23; scripts/generate-nano-banana.py:10-11,18-26,50-52,75-78
Vulnerability Type: Unvalidated service endpoint override and credential disclosure
Risk Level: Medium

Vulnerable Code

generate.sh:11,98-101:

bash
API_BASE="${PIXELDOJO_API_BASE:-https://pixeldojo.ai/api/v1}"

SUBMIT_RESPONSE=$(curl -sS -X POST "${API_BASE}/models/${MODEL}/run" \
    -H "Authorization: Bearer ${API_KEY}" \
    -H "Content-Type: application/json" \
    -d "$(build_payload)")

models.sh:6-14:

bash
API_BASE="${PIXELDOJO_API_BASE:-https://pixeldojo.ai/api/v1}"
API_KEY="${PIXELDOJO_API_KEY:-}"

CURL_ARGS=(-sS "${API_BASE}/models")
if [[ -n "$API_KEY" ]]; then
  CURL_ARGS+=( -H "Authorization: Bearer ${API_KEY}" )
fi

RESPONSE=$(curl "${CURL_ARGS[@]}")

status.sh:7,22-23:

bash
API_BASE="${PIXELDOJO_API_BASE:-https://pixeldojo.ai/api/v1}"

curl -sS "${API_BASE}/jobs/${JOB_ID}" \
    -H "Authorization: Bearer ${API_KEY}" | jq .

scripts/generate-nano-banana.py:10-11,18-26:

python
API_KEY = os.environ.get("PIXELDOJO_API_KEY")
API_BASE = os.environ.get("PIXELDOJO_API_BASE", "https://pixeldojo.ai/api/v1")

def http_json(method, url, payload=None, timeout=60):
    data = None
    headers = {"Authorization": f"Bearer {API_KEY}"}
    if payload is not None:
        data = json.dumps(payload).encode("utf-8")
        headers["Content-Type"] = "application/json"
    request = urllib.request.Request(url, data=data, headers=headers, method=method)
    try:
        with urllib.request.urlopen(request, timeout=timeout) as response:

Technical Analysis

PIXELDOJO_API_BASE is treated as a trusted destination even though it is supplied through the process environment. The code does not validate its scheme, hostname, port, or embedded user-information before att ...[truncated 1845 chars]

Remediation
View remediation

Remediation Suggestions

  1. Permit only https API endpoints.
  2. Allowlist the expected PixelDojo hostname, such as pixeldojo.ai, and any separately documented trusted API hosts.
  3. Reject embedded credentials, fragments, unexpected ports, malformed URLs, and hosts that resolve to loopback, private, link-local, or reserved addresses.
  4. Validate the destination before constructing or attaching the authorization header.
  5. If custom endpoints are needed for development, require an explicit opt-in flag and a separate test credential rather than silently honoring an unrestricted environment variable.
  6. Configure redirect handling so credentials cannot be forwarded to a different host.
  7. Avoid printing sensitive response bodies where API errors could contain confidential account information.

T09 · Insecure Skill Coding Practices

Warning
Location
generate.sh:143
Finding

Unvalidated Output URLs Permit Unsafe Network Requests and Arbitrary Response Downloads

Content
View full analysis

Vulnerability Details

File Location: generate.sh:143-174; scripts/generate-nano-banana.py:88-93,108-125
Vulnerability Type: Untrusted URL fetch and client-side server-side request forgery behavior
Risk Level: Medium

Vulnerable Code

generate.sh:143-174:

bash
OUTPUT_URL=$(echo "$STATUS_RESPONSE" | jq -r '.output.image // .output.video // .output.images[0] // .output.videos[0] // empty')

if [[ -z "$OUTPUT_URL" || "$OUTPUT_URL" == "null" ]]; then
    echo "Error: No output URL found in job response"
    echo "Response: $STATUS_RESPONSE"
    exit 1
fi

if [[ "$TYPE" == "video" ]]; then
    EXT="mp4"
    SUBDIR="videos"
else
    EXT="png"
    SUBDIR="images"
fi

mkdir -p "${OUTPUT_DIR}/${SUBDIR}"

TIMESTAMP=$(date +%Y%m%d_%H%M%S)
PROMPT_SNIPPET=$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]' | tr ' ' '_' | cut -c1-30 | sed 's/[^a-z0-9_]//g')
FILENAME="${TIMESTAMP}_${PROMPT_SNIPPET}.${EXT}"

if [[ -n "$CUSTOM_OUTPUT" ]]; then
    OUTPUT_PATH="$CUSTOM_OUTPUT"
    mkdir -p "$(dirname "$OUTPUT_PATH")"
else
    OUTPUT_PATH="${OUTPUT_DIR}/${SUBDIR}/${FILENAME}"
fi

echo ""
echo "Downloading result..."
curl -sS -L "$OUTPUT_URL" -o "$OUTPUT_PATH"

scripts/generate-nano-banana.py:88-93,108-125:

python
if state == "completed":
    output_data = status.get("output", {})
    images = output_data.get("images", [])
    if images:
        output_url = images[0]
        print(f"Generation complete. URL: {output_url}")
        break

if args.output:
    out_path = args.output
else:
    timestamp = time.strftime("%Y%m%d_%H%M%S")
    out_path = f"{os.path.expanduser('~/Pictures/AI Generated/images')}/{timestamp}_nano_banana_gen.png"

os.makedirs(os.path.dirname(os.path.abspath(out_path)), exist_ok=True)

print(f"Downloading to {out_path}...")
try:
    download_status, content = http_download(output_url, timeout=120)
except urllib.error.HTTPError
...[truncated 2860 chars]
Remediation
View remediation

Remediation Suggestions

  1. Accept output URLs only over HTTPS.
  2. Allowlist documented PixelDojo asset-storage hostnames rather than accepting arbitrary destinations.
  3. Resolve the hostname and reject loopback, private, link-local, multicast, unspecified, and reserved IP ranges for both IPv4 and IPv6.
  4. Revalidate the scheme, hostname, port, and resolved address after every redirect. Prefer disabling redirects unless they are required.
  5. In Bash, terminate option parsing explicitly:
    bash
    curl --fail --silent --show-error --location --output "$OUTPUT_PATH" -- "$OUTPUT_URL"
    
  6. Apply strict maximum response-size and timeout limits.
  7. Validate Content-Type and inspect file signatures before accepting the response as PNG, video, or other generated media.
  8. Download to a newly created temporary file with restrictive permissions, validate it, and atomically move it to the final destination.
  9. Remove partial output files when validation or download fails.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (10)

Tainted flow: 'request' from os.environ.get (line 24, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/generate-nano-banana.py (reported line 26)May include surrounding context.

python
headers["Content-Type"] = "application/json"
    request = urllib.request.Request(url, data=data, headers=headers, method=method)
    try:
        with urllib.request.urlopen(request, timeout=timeout) as response:
            body = response.read().decode("utf-8")
            return response.status, body, json.loads(body)
    except urllib.error.HTTPError as exc:

Tainted flow: 'request' from os.environ.get (line 24, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/generate-nano-banana.py (reported line 36)May include surrounding context.

python
headers["Content-Type"] = "application/json"
    request = urllib.request.Request(url, data=data, headers=headers, method=method)
    try:
        with urllib.request.urlopen(request, timeout=timeout) as response:
            body = response.read().decode("utf-8")
            return response.status, body, json.loads(body)
    except urllib.error.HTTPError as exc:

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The description says the skill helps choose from a live catalog and download assets, but it does not clearly disclose that it writes files locally and may rely on helper scripts rather than implementing safe, explicit browsing logic. Description-behavior mismatches are dangerous because they can cause agents or users to approve a skill under incomplete assumptions about network access and filesystem side effects.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 38)May include surrounding context.

Optional local env file:

bash
cp ~/.openclaw/skills/pixeldojo/.env.example ~/.openclaw/skills/pixeldojo/.env

Default API base: https://pixeldojo.ai/api/v1

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill declares requirements for environment variables and shell/network-capable binaries, but it does not declare an explicit tool scope or permissions boundary. That makes the skill harder to safely govern and increases the risk that an agent can invoke networked shell actions or access secrets without clear user-facing authorization.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 3)May include surrounding context.

md
---
name: pixeldojo
description: Access PixelDojo's API for AI image and video generation. Use when an agent needs to create images or videos, choose a model from the live PixelDojo catalog, check async job status, or download finished assets. PixelDojo is a subscription-based creative platform that exposes multiple generation models through one API, including general image, editing-oriented image, and video workflows.
metadata:
  author: Brian Lovett
  homepage: https://pixeldojo.ai

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill instructs users to set an API key and submit prompts, but it does not clearly warn that prompts, image URLs, and related generation inputs will be transmitted to PixelDojo's external service. This creates a data-handling risk because users may provide sensitive prompts or private asset URLs without understanding they leave the local environment.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · generate.sh (reported line 98)May include surrounding context.

sh
echo "Model: $MODEL"
echo "Prompt: $PROMPT"

SUBMIT_RESPONSE=$(curl -sS -X POST "${API_BASE}/models/${MODEL}/run" \
    -H "Authorization: Bearer ${API_KEY}" \
    -H "Content-Type: application/json" \
    -d "$(build_payload)")

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

This shell script creates directories and writes downloaded output files to either a default Pictures folder or a caller-supplied path. While it prints progress messages, there is no user-facing warning or explanatory comment/docstring disclosing that the skill persists files locally, which is a safety-relevant side effect for a generator utility.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The skill documents default output folders for generated assets but does not explicitly warn that running the helpers will create files automatically on local disk. Undisclosed file creation is a safety concern because it can surprise users, consume storage, or place sensitive/generated content in persistent locations.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.