Back to skill

Security audit

blog-polish-eng-images

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed blog-polishing helper, but its file-writing path is under-scoped and its runnable workflow does not match the advertised polishing behavior.

Install only if you are comfortable with it reading the configured draft file and saving durable outputs under the OpenClaw workspace. Use a trusted output directory and avoid custom subject values containing path characters; also expect that the current runnable workflow may produce placeholder content unless the hosting agent follows the later natural-language instructions instead.

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
SKILL.md:101
Finding

Unvalidated Subject Allows Conditional Output Path Traversal

Content
View full analysis
1 && echo "More content..." || echo ""))\n\n## Summary\n- Sections: $sections\n- Length: ~$wordcount words" polishedPath="$outputDir/${ts}-${subject}.md" echo -e "$polished_content" > "$polishedPath" save_state polishedPath subject ``` ### Technical Analysis The automatically inferred `subject` is converted into a restricted slug, but a caller-supplied `input_subject` bypasses that sanitization entirely. It may therefore contain path separators, `..` components, control characters, or other unsafe filename characters. The unvalidated value is interpolated into `polishedPath` and used as the destination of a shell redirection. Quoting the path prevents shell command injection, but it does not prevent filesystem path traversal. The timestamp is prepended to the subject, which prevents a simple value such as `../../target` from immediately becoming a parent-directory traversal: its first path component becomes something similar to `2609161200-..`. Exploitation is nevertheless possible when the attacker can prepare a matching intermediate directory or symbolic link under the output directory. Timestamps are predictable to the minute, making such preparation feasible where the attacker has access to the output directory. ### Attack Path 1. The attacker can control `input_subject` and can create files, directories, or symbolic links inside the selected output directory. 2. The a ...[truncated 1787 chars]
Remediation
View remediation
&2 exit 1 fi ``` 2. Explicitly reject path separators, traversal components, and control characters before constructing the output path: ```sh case "$subject" in *"/"*|*".."*|*"\\"*) echo "Invalid subject" >&2 exit 1 ;; esac ``` 3. Enforce a clear allowlist, such as: ```text ^[a-z0-9][a-z0-9-]{0,63}$ ``` 4. Canonicalize `outputDir` and the destination parent, then verify that the resolved destination remains beneath the canonical output directory. This check should also account for symbolic links. 5. Reject a destination if it already exists as a symbolic link. Where supported, use file-creation mechanisms that do not follow symlinks and consider refusing to overwrite existing files. 6. Replace `echo -e` with `printf` to avoid implementation-dependent escape processing: ```sh printf '%s\n' "$polished_content" > "$polishedPath" ``` 7. Add tests covering subjects containing `/`, `\`, `..`, absolute-looking paths, newlines, Unicode separators, oversized values, and prepared symbolic links. ]]>
Vulnerability Patterns
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Rogue AgentSelf-Modification, Session Persistence
  • 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
Findings (9)

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest description says the skill will polish a draft into a specific-length en-US article while preserving technical terms and structure. In practice, the workflow constructs hardcoded placeholder text such as 'Content polished and restructured...' and 'Technical details preserved...', uses the original title and section count, and never performs translation, substantive editing, or length enforcement.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest description requires producing an "en-US article," which imposes a specific locale by default. This is reinforced elsewhere in the file and does not offer an explicit user choice or opt-in, matching the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The comment explicitly describes behavior that the code does not carry out. The generated markdown is a short static template with Introduction, Section 1, optional Section 2, and Summary, and it uses the original word count in a summary rather than producing or checking a 1000–1200 word article.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest and documentation promise consistent hero and per-section prompts tied to the article's real sections. The implementation does not parse actual section headings from the polished article and instead emits generic prompts like 'Section 1: key concept diagram', so the returned prompts are not grounded in the blog content as described.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The skill is designed to persist user-provided or derived content to a timestamped path under a shared workspace, creating durable artifacts across sessions. Persistent storage can expose sensitive draft content, internal code snippets, or proprietary material to later sessions, other skills, or users if workspace isolation and retention controls are weak.

Content

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

md
- **Structure**: reorganize into **3–4 sections total** (not more)
- **Length**: final content **1000–1200 words**
- **Images**: generate a **hero prompt** + **one prompt per section**, all in the same style/tone
- **Save**: write everything to `~/.openclaw/workspace/contentPolished/` using `yymmddhhmm-*` naming

## When to Use This Skill

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The usage guidance says the skill should be used when the user wants a polished en-US version, but the overall skill definition and title frame en-US as the expected output behavior rather than an optional locale choice. This is a natural-language locale constraint without documented opt-in handling.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The workflow explicitly creates timestamped files in a stable home-directory workspace, which increases traceability and accumulation of potentially sensitive content over time. If the environment reuses workspaces or allows cross-session access, this can leak prior drafts and generated artifacts beyond the intended execution context.

Content

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

  1. Resolve defaults:
    • draftPath = input.draftPath || "~/.openclaw/workspace/contentDraft/latestDraft.md"
    • outputDir = input.outputDir || "~/.openclaw/workspace/contentPolished/"
  2. Create a timestamp prefix ts in yymmddhhmm format (Linux/macOS):
text
date +"%y%m%d%H%M"

Unbounded Output

Medium
Category
Output Handling
Confidence
60% confidence
Finding

Output size or generation rate is not bounded. Unbounded output enables denial-of-service through resource exhaustion, log flooding, or context-window stuffing.

Content

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

md
- Add missing connective tissue *only* where the meaning is unclear
- **Do not reduce content** (no big deletions)

### Step 4 — Enforce Length (1000–1200 Words) Without Cutting Meaning

Target final length 1000–1200 words (counting English words approximately by rough equivalence).

Session Persistence

Medium
Category
Rogue Agent
Confidence
91% confidence
Finding

The save instructions require writing the polished markdown and image filenames to deterministic persistent locations, extending the lifetime of user content and metadata. In a multi-tenant or loosely isolated agent environment, those files can become an unintended disclosure channel for sensitive drafts or subjects inferred from titles.

Content

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

md
1. Decide `subject`:
   - `subject = input.subject || slugify(title)` (lowercase, hyphens)
2. Write the polished markdown:
   - `{{outputDir}}/{{ts}}-{{subject}}.md`
3. Determine image filenames:
   - Hero: `{{ts}}-main.png`