Back to skill

Security audit

Dynamic UI

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but its renderer can make under-documented network requests and persist rendered user data to disk.

Review before installing. Use this only in an environment where wkhtmltoimage cannot reach sensitive internal services, avoid rendering untrusted card image URLs, avoid putting secrets in rendered data, and periodically clean any files written under ~/.openclaw/media or other output paths.

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/render.sh:19
Finding
Unrestricted Card Image URL Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/render.sh:19-31`, `scripts/render.sh:216-229`, `scripts/render.sh:393-401`; related sink in `templates/card.html:70` **Vulnerability Type**: Server-Side Request Forgery (SSRF) through an insufficiently validated image URL **Risk Level**: Medium ### Vulnerable Code ```bash # HTML entity escaping for user-supplied text escape_html() { echo "$1" | sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g; s/"/\&quot;/g; s/'"'"'/\&#39;/g' } # Validate image URL (block dangerous protocols) validate_image_url() { local url="$1" # Block file://, javascript:, data: (except data:image), and vbscript: if [[ "$url" =~ ^(file:|javascript:|vbscript:) ]]; then echo "" return fi if [[ "$url" =~ ^data: ]] && [[ ! "$url" =~ ^data:image/ ]]; then echo "" return fi echo "$url" } ``` ```bash generate_card() { local data="$1" TITLE=$(echo "$data" | jq -r '.title // ""') SUBTITLE=$(echo "$data" | jq -r '.subtitle // ""') BODY=$(echo "$data" | jq -r '.body // ""') STATUS=$(echo "$data" | jq -r '.status // ""') IMAGE=$(echo "$data" | jq -r '.image // ""') # Escape all user-supplied text TITLE=$(escape_html "$TITLE") SUBTITLE=$(escape_html "$SUBTITLE") BODY=$(escape_html "$BODY") IMAGE_HTML="" if [[ -n "$IMAGE" && "$IMAGE" != "null" ]]; then # Validate image URL (block dangerous protocols) IMAGE=$(validate_image_url "$IMAGE") if [[ -n "$IMAGE" ]]; then IMAGE=$(escape_html "$IMAGE") IMAGE_HTML="<img src=\"$IMAGE\" class=\"card-image\" />" fi fi ``` ```html <body> <div class="card"> {{IMAGE_HTML}} ``` ```bash # Render with wkhtmltoimage /usr/bin/wkhtmltoimage \ --quiet \ --width "$WIDTH" \ --enable-javascript \ --javascript-delay 500 \ --format png \ "$TEMP_DIR/render.html" \ "$OUTPUT_FILE" ``` ### Technical Analysis The c ...[truncated 3320 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Disable remote images by default.** Accept embedded image data only after strict MIME-type, decoding, and size validation, or remove the `image` feature if it is unnecessary. 2. **Use an explicit allowlist if remote images are required.** - Parse the URL with a dedicated URL parser rather than shell regular expressions. - Permit only `https`. - Normalize the scheme and hostname before validation. - Allow only explicitly trusted image hosts. - Reject URLs containing credentials or ambiguous host syntax. 3. **Block internal destinations.** - Resolve the hostname before connecting. - Reject loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 ranges. - Block cloud metadata endpoints. - Revalidate every redirect target and every DNS resolution result to prevent redirect and DNS-rebinding bypasses. 4. **Fetch images outside the HTML renderer.** Use a hardened downloader in a network-isolated process with: - Strict connection and total timeouts. - Redirect limits. - Response-size limits. - MIME-type and image-decoding validation. - Proxy restrictions. - Egress filtering. - A nonprivileged execution account. Save the validated result to a controlled temporary path and reference only that file during rendering. 5. **Harden `wkhtmltoimage`.** - Replace `--enable-javascript` with `--disable-javascript`. - Explicitly disable local file access where supported. - Run the renderer in a sandbox or container without access to sensitive files or internal networks. - Apply operating-system resource limits. 6. **Document the capability.** If card images remain supported, include the `image` field and its network behavior in `README.md` and `SKILL.md` so operators can make an informed trust decision. 7. **Add security tests** covering uppercase schemes, protocol-relative URLs, redirects, IPv4 and IPv6 loopback addresses, private ranges, link-loca ...[truncated 140 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
# Ubuntu/Debian
sudo apt-get install -y wkhtmltopdf jq fonts-noto-color-emoji

# macOS
brew install wkhtmltopdf jq
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
label: "Install wkhtmltoimage + jq (brew)"
    installHint: |
      This skill requires wkhtmltoimage and jq. Install with:
      Ubuntu/Debian: sudo apt-get install -y wkhtmltopdf jq fonts-noto-color-emoji
      macOS: brew install wkhtmltopdf jq
---
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger list includes generic verbs like 'render', 'visualize', and 'chart', which are common in normal conversation and can cause the skill to activate unexpectedly. In an agent setting, unintended activation can lead to unplanned file generation, tool invocation, or downstream handling of user data, increasing the chance of privacy or operational issues.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The documentation explicitly recommends saving rendered images under ~/.openclaw/media/ and then sending them to users, but it does not warn that rendered outputs may persist on disk and may contain sensitive input data. Because the skill renders arbitrary user-provided content into files, this creates a realistic risk of residual sensitive data exposure, accidental disclosure, or reuse of files beyond the original request.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
This script renders attacker-influenced HTML and explicitly enables JavaScript in wkhtmltoimage. Although many fields are HTML-escaped, remote images are still allowed and the renderer is a browser engine; enabling script execution unnecessarily increases the attack surface for script execution, SSRF-like network access, and exploitation of wkhtmltoimage/WebKit behaviors during rendering. In the context of an image-rendering skill, JavaScript is not required for the implemented templates, so this is more dangerous than the claimed functionality suggests.

Missing User Warnings

Low
Confidence
77% confidence
Finding
The script accepts a caller-controlled output path and writes the rendered PNG to that location via wkhtmltoimage. Although this is part of rendering behavior, the code provides no confirmation prompt or user-facing notice at the point of the file write beyond echoing the path afterward.

Static analysis

No suspicious patterns detected.