Back to skill

Security audit

Drip director

Security checks for vulnerabilities and agentic risk

Overview

This image-production skill is coherent overall, but it needs review because it can send image data to external AI services and has unsafe local file handling that could process or delete the wrong files.

Install only if you are comfortable with your generated images, briefs, and constraints being sent to Google Gemini and with the skill invoking local image-generation scripts. Prefer a version that obtains exact attachment paths from trusted session metadata, uses private temporary directories, pins or verifies the generator, and validates all cleanup paths before deletion.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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

Warning
Location
SKILL.md:122
Finding
Unreliable Reference Image Discovery Can Expose Unrelated Private Media<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:122-130` **Vulnerability Type**: Reference confusion and unintended data disclosure **Risk Level**: Medium ### Vulnerable Code ```markdown **Also capture local file paths of the reference images:** ```bash ls -t1 ~/.openclaw/media/inbound/ | head -20 ``` The N most recently listed files (where N = number of images the user sent) are the reference images. Store their full absolute paths in `CREATIVE_BRIEF.reference_images`. Example entry: `/Users/inimene/.openclaw/media/inbound/file_6---abc123.jpg` ``` ### Technical Analysis The skill determines which images belong to the current request by listing a shared inbound-media directory and selecting its most recently modified entries. File modification order does not establish that a file belongs to the current user, message, or pipeline session. Concurrent uploads, stale files with updated timestamps, or files deliberately placed in the inbound directory can therefore be mistaken for current reference images. The selected paths are subsequently passed to the image-generation workflow. The resulting generated image may also be sent to the external Gemini critique API, potentially propagating visual information derived from the incorrectly selected reference. There is no documented validation of file ownership, session association, expected filename, MIME type, or canonical path. ### Attack Path 1. A victim submits an image-generation request containing one or more reference images. 2. Before the skill runs its directory listing, another process or user places a sensitive or attacker-selected image in `~/.openclaw/media/inbound/`, or updates an existing file's timestamp. 3. The command sorts the directory by modification time and treats the newest entries as the victim's references. 4. The unrelated image path is stored in `CREATIVE_BRIEF.reference_images`. 5. The image is sent to the configured generation service as an input. 6. A generated deriva ...[truncated 472 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Obtain attachment paths exclusively from trusted metadata associated with the current message and session. - Do not infer attachment identity from directory modification times. - Bind each selected file to a user, conversation, and request identifier. - Canonicalize each path and require it to reside within the expected media directory. - Validate that each reference is a regular, non-symlink image file with an allowed MIME type and size. - Reject files that are not explicitly associated with the current request. - Present the selected references for confirmation before transmitting them to an external service when reliable attachment metadata is unavailable. - Clearly disclose which external services receive image data and obtain user consent where required. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:261
Finding
Predictable Shared Temporary Files Permit Symlink Attacks and Sensitive Data Retention<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:261-296` **Vulnerability Type**: Unsafe temporary-file handling **Risk Level**: Medium ### Vulnerable Code ```bash # Write CREATIVE_BRIEF to temp file (safe multiline — no quoting issues) cat > /tmp/sd-brief.txt << 'SD_BRIEF_EOF' [paste current PIPELINE_STATE.CREATIVE_BRIEF content here] SD_BRIEF_EOF # Write CONSTRAINT_HIERARCHY to temp file cat > /tmp/sd-constraints.txt << 'SD_CONSTRAINTS_EOF' [paste current PIPELINE_STATE.CONSTRAINT_HIERARCHY content here] SD_CONSTRAINTS_EOF # Image path from PIPELINE_STATE — use ITERATION_LOG[n].file_path IMAGE_PATH="[PIPELINE_STATE.ITERATION_LOG[n].file_path]" IMAGE_B64=$(base64 -i "$IMAGE_PATH" | tr -d '\n') # Build JSON payload using jq — no manual escaping PAYLOAD=$(jq -n \ --rawfile brief /tmp/sd-brief.txt \ --rawfile constraints /tmp/sd-constraints.txt \ --arg b64 "$IMAGE_B64" \ '{contents:[{parts:[ {text:("You are a forensic image quality critic. Evaluate the generated image against the brief and constraint hierarchy. Identify only concrete, visible deviations. Do not suggest prompt edits. Report only what you observe.\n\nCREATIVE BRIEF:\n"+$brief+"\nCONSTRAINT HIERARCHY:\n"+$constraints+"\n\nOutput in EXACTLY this format:\n\nACCURATE_ELEMENTS:\n- [what matches the brief]\n\nCRITICAL_DEVIATIONS (identity breaks, brand failures):\n- [each deviation]\n\nMAJOR_DEVIATIONS (significant but not identity-breaking):\n- [each deviation]\n\nMINOR_DEVIATIONS (stylistic drift, acceptable variance):\n- [each deviation]\n\nCONFIDENCE_SCORE: [0-100]\n\nSIMILARITY_ESTIMATES:\n face_preservation: [0.0-1.0]\n pose_preservation: [0.0-1.0]\n logo_integrity: [0.0-1.0]")}, {inline_data:{mime_type:"image/png",data:$b64}} ]}]}') # Call Gemini API — capture HTTP status and body separately HTTP_STATUS=$(curl -s -w "%{http_code}" -o /tmp/sd-critique.json \ "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=$GOOG ...[truncated 2342 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create a private temporary directory with `mktemp -d` rather than using fixed paths. - Set `umask 077` before creating files so only the current account can access them. - Store all temporary files beneath the private directory. - Use exclusive file creation and refuse symbolic links. - Register an exit handler such as `trap 'rm -rf -- "$TMP_DIR"' EXIT HUP INT TERM`. - Validate that temporary files are regular files owned by the current user before reading them. - Avoid persisting sensitive data where possible; construct the request through protected pipes or in-memory processing. - Use unique files per execution to prevent collisions between simultaneous sessions. - Avoid placing credentials in query strings where feasible; use the API's supported authentication header because URLs may appear in diagnostics or proxy logs. ]]>

T07 · Tool Hijacking and Spoofing

Warning
Location
SKILL.md:207
Finding
Untrusted Generator Output Is Later Used as Destructive Cleanup Authority<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:207-221, 425-436` **Vulnerability Type**: Tool spoofing leading to arbitrary file deletion **Risk Level**: Medium ### Vulnerable Code ```bash NBP=$(find ~/.openclaw/skills/nano-banana-pro/scripts /usr/local/lib/node_modules/openclaw/skills/nano-banana-pro/scripts -name "generate_image.py" 2>/dev/null | head -1) uv run "$NBP" \ --prompt "[HARDENED PROMPT from Stages 2–3]" \ --api-key "$GOOGLE_API_KEY" \ -i "[CREATIVE_BRIEF.reference_images[0]]" \ -i "[CREATIVE_BRIEF.reference_images[1]]" \ --filename "dd-$(date +%s)" \ --resolution 1K ``` ```markdown - Parse the `MEDIA:` path from script output and record it in `ITERATION_LOG[n].file_path` for cleanup at convergence ``` ```markdown After upscale generation: 1. **Delete all intermediate iteration files** — run `rm` on every file_path in ITERATION_LOG except the upscaled file just generated ``` ```markdown #### If skip: 1. **Delete all intermediate iteration files** — run `rm` on every file_path in ITERATION_LOG except GENERATED_IMAGE_V[n] (the accepted 1K) ``` ### Technical Analysis The skill dynamically discovers `generate_image.py`, prioritizing the user-local OpenClaw skill directory because it is searched first. It then trusts a `MEDIA:` path printed by that executable and stores the value for later deletion. No requirement is provided to authenticate the generator, pin its expected location or digest, canonicalize the returned path, or verify that it belongs to a dedicated output directory. Consequently, a replaced, spoofed, or compromised generator can emit an arbitrary path. The convergence procedure later instructs the agent to invoke `rm` on that path. This creates a trust-boundary violation: output from an executable dependency controls a later destructive filesystem operation. ### Attack Path 1. An attacker who can modify or introduce files under the searched user-local skill directory places a spoofed `generate_image ...[truncated 1058 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin the generator to one administrator-approved absolute path rather than dynamically selecting the first search result. - Verify the generator's owner, permissions, signature, or cryptographic digest before execution. - Do not allow a tool's stdout to serve directly as authorization for file deletion. - Create a dedicated output directory for each pipeline execution and retain its canonical path. - Canonicalize every reported media path with a safe path-resolution API. - Require every deletion candidate to be a regular, non-symlink file located strictly beneath the dedicated output directory. - Reject empty paths, relative paths, paths containing traversal, filesystem roots, and any path outside the approved directory. - Track generated files using file descriptors or trusted controller-created paths rather than generator-reported paths. - When shell deletion is unavoidable, use `rm -- "$validated_path"` after validation to prevent option interpretation. - Prefer deleting the controller-owned temporary output directory as a unit after confirming that it is not a symlink and has the expected owner. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

Session Persistence

Medium
Category
Rogue Agent
Content
**Question sequence:**

1. **What do you want changed?**
   Examples: "Swap the outfit only — keep everything else identical" / "Change background to outdoor" / "Create entirely new composition"

2. **Where will this image be used? (determines aspect ratio)**
   Examples: Instagram post (1:1) / Instagram Story or TikTok (9:16) / website banner (16:9) / e-commerce product page (4:5) / print / other
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.

External Transmission

Medium
Category
Data Exfiltration
Content
]}]}')

# Call Gemini API — capture HTTP status and body separately
HTTP_STATUS=$(curl -s -w "%{http_code}" -o /tmp/sd-critique.json \
  "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=$GOOGLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$PAYLOAD")
Confidence
95% confidence
Finding
The skill sends a base64-encoded generated image plus the creative brief and constraints to an external Gemini API endpoint. This is an external data transmission vulnerability when users may not understand that their images and associated content are being exported to a third party, potentially including sensitive or proprietary material.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill instructs automatic deletion of generated files via rm without clearly warning the user beforehand or obtaining explicit confirmation for destructive cleanup. In an agent setting, silent file deletion can cause unexpected data loss, especially if iteration logs or file paths are wrong or broader than intended.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
**Default (Interactive):** Confirm every stage. Full output at each step.

**Fast Mode (user must explicitly request):**
User says "fast mode" → auto-advance through Stages 2–3 without confirmation.
Generation (Stage 4) and Critique (Stage 5) always require confirmation regardless of mode.

---
Confidence
75% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Intent-Code Divergence

Low
Confidence
92% confidence
Finding
The manifest description states that every stage requires explicit user confirmation. Later instructions define a Fast Mode where stages 2–3 proceed automatically, which directly contradicts that blanket claim rather than merely adding implementation detail.

Intent-Code Divergence

Low
Confidence
88% confidence
Finding
The termination instruction says to exit drip-director mode completely, but then says pipeline logic should not resume unless the user explicitly invokes 'shot-director' again. That contradicts the skill's own declared name 'drip-director' and creates intent ambiguity about how the mode is re-entered.

Static analysis

No suspicious patterns detected.