Back to skill

Security audit

OpenClaw Warden Pro

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real local security tool, but it recommends automatic startup remediation that can overwrite workspace files or disable skills without review.

Install only if you are comfortable with a local tool that can overwrite monitored instruction/config files and rename skill directories. Do not enable the startup hook or heartbeat automation until restore paths are confined, symlinks are rejected, protect defaults to report-only, and destructive actions require explicit approval.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/integrity.py:616
Finding
Path Traversal Allows Restore Operations Outside the Workspace<![CDATA[ ## Vulnerability Details **File Location**: `scripts/integrity.py`, lines 616-626 **Vulnerability Type**: Improper path confinement in filesystem restore operation **Risk Level**: High ### Vulnerable Code ```python def cmd_restore(workspace: Path, filepath: str): """Restore a file from its baseline snapshot.""" rel = filepath.replace("\\", "/") snap = get_snapshot_path(workspace, rel) if snap is None: print(f"No snapshot found for: {rel}") print("Only critical, config, and skill files are snapshotted.") sys.exit(1) dest = workspace / rel import shutil shutil.copy2(snap, dest) ``` ### Technical Analysis The user-controlled `filepath` is normalized only by replacing backslashes. The implementation does not reject absolute paths or `..` path components, resolve the resulting path, or verify that the resolved destination remains inside `workspace`. The snapshot source is formed relative to `.integrity/snapshots`, while the destination is formed relative to the workspace root. Because these base paths have different depths, a traversal path can resolve the source and destination to different locations outside their intended roots. If the resolved source exists as a regular file, `shutil.copy2()` can copy it to an unintended destination outside the workspace. The same unvalidated path construction pattern also appears in `cmd_accept` at lines 586-587 and `cmd_rollback` at lines 645-646. Although those operations have additional constraints, all file-oriented commands should share a single strict path-validation routine. ### Attack Path 1. An attacker influences the file argument passed to `restore`, such as through malicious workspace instructions or an unsafe Agent-generated tool call. 2. The argument contains enough `../` components to escape `.integrity/snapshots` and the workspace. 3. `get_snapshot_path()` resolves the source traversal and accepts it if the resulting path is a file. 4. `worksp ...[truncated 865 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Reject absolute paths and any path containing `..` before performing filesystem operations. - Resolve the workspace, snapshot root, source, and destination with `Path.resolve()`. - Enforce containment using `Path.is_relative_to()` or an equivalent compatibility helper: ```python def confined_path(root: Path, user_path: str) -> Path: relative = Path(user_path.replace("\\", "/")) if relative.is_absolute() or ".." in relative.parts: raise ValueError("Absolute paths and traversal are not allowed") root = root.resolve() candidate = (root / relative).resolve() if not candidate.is_relative_to(root): raise ValueError("Path escapes the authorized root") return candidate ``` - For `restore`, accept only relative paths already recorded in the integrity manifest. - Independently validate the snapshot source under `.integrity/snapshots` and the destination under the workspace. - Apply the same centralized validation to `accept`, `restore`, and `rollback`. - Revalidate paths immediately before writing to reduce time-of-check/time-of-use exposure. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/integrity.py:772
Finding
Symlink-Following Restore Can Overwrite External Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/integrity.py`, lines 772-776 **Vulnerability Type**: Unsafe symlink handling in an automatic file restoration operation **Risk Level**: High ### Vulnerable Code ```python files_to_restore = (modified_critical & injected_files) | modified_critical for rel in sorted(files_to_restore): snap = get_snapshot_path(workspace, rel) if snap: import shutil dest = workspace / rel shutil.copy2(snap, dest) ``` The equivalent unsafe destination write is also present in the manual restore command at lines 624-626: ```python dest = workspace / rel import shutil shutil.copy2(snap, dest) ``` ### Technical Analysis The code does not use `lstat()` or otherwise reject symbolic links before restoring a file. By default, `shutil.copy2(source, destination)` follows a destination symlink and writes the snapshot content to the symlink's target. A monitored path can therefore appear to be inside the workspace while redirecting the actual write to a file outside it. Path-string checks alone would not fully remediate this issue because an apparently valid in-workspace path can contain a symlink in its final component or in an intermediate directory. The risk is amplified in `protect`, which is recommended for automatic execution at session startup and can perform the restore without interactive confirmation. ### Attack Path 1. An attacker able to alter workspace contents replaces a monitored critical file with a symbolic link to an external file writable by the Agent process. 2. The monitored path differs from its baseline or otherwise enters the modified-critical set. 3. The startup hook or user invokes `protect`, or the user invokes `restore` manually. 4. The implementation constructs the destination path but does not inspect it for symlinks. 5. `shutil.copy2()` follows the symlink. 6. Baseline snapshot content overwrites the external symlink target. ### Impact Assessment The Skill ca ...[truncated 587 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Reject symbolic links at the destination and in every path component. - Inspect paths using `os.lstat()` rather than APIs that automatically follow symlinks. - Resolve and verify the destination under the workspace, but do not rely on resolution alone where path components can be replaced concurrently. - Open the destination using platform-appropriate no-follow semantics, such as `O_NOFOLLOW` where available. - Write to a securely created temporary regular file inside a verified directory and atomically replace the intended regular file. - Before replacement, verify that the destination parent is still the expected directory and that the destination has not become a symlink. - Refuse automatic restoration if the monitored path's filesystem type changed from a regular file. - Record and report symlink findings as critical rather than attempting automatic remediation through the link. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/integrity.py:770
Finding
Protection Sweep Unconditionally Reverts All Modified Critical Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/integrity.py`, lines 770-776 **Vulnerability Type**: Unsafe automatic remediation and unintended destructive behavior **Risk Level**: Medium ### Vulnerable Code ```python # Restore critical files that were modified and have injections files_to_restore = (modified_critical & injected_files) | modified_critical for rel in sorted(files_to_restore): snap = get_snapshot_path(workspace, rel) if snap: import shutil dest = workspace / rel shutil.copy2(snap, dest) ``` ### Technical Analysis The comment states that restoration applies to critical files that were both modified and found to contain injection patterns. The set expression does not implement that condition: ```python (modified_critical & injected_files) | modified_critical ``` For any sets `A` and `B`, `(A & B) | A` simplifies to `A`. Consequently, `files_to_restore` always contains every modified critical file, regardless of whether the injection scanner identified a threat. Integrity verification detects only a hash mismatch. It cannot distinguish malicious tampering from a legitimate edit made after the baseline. Therefore, the recommended startup `protect` hook can silently replace valid changes to critical workspace files with stale snapshots. ### Attack Path 1. A user or authorized tool legitimately edits a monitored critical file after the baseline is established. 2. The manifest still contains the previous hash and snapshot. 3. The recommended session-start hook automatically invokes `protect`. 4. Integrity verification classifies the file as modified. 5. The set expression adds the file to `files_to_restore` even when no injection is detected. 6. The current content is overwritten by the baseline snapshot without confirmation or preservation. 7. Repeated startup sweeps can continue undoing intended changes until the baseline is manually updated. An attacker could also exploit user reliance on autom ...[truncated 741 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Correct the restoration condition to match the documented intent: ```python files_to_restore = modified_critical & injected_files ``` - Do not treat a hash mismatch alone as proof of malicious modification. - Require explicit confirmation before reverting files that have no high-confidence malicious indicators. - Preserve the current file in a timestamped, non-executable recovery area before any automatic overwrite. - Generate and display a content diff against the snapshot before remediation. - Add a dry-run mode and make it the default for startup hooks. - Maintain a transaction log containing the original hash, replacement hash, reason, timestamp, and recovery location. - Prefer flagging uncertain changes for review rather than automatically reverting them. - Add regression tests proving that: - modified files without injection findings are not restored; - modified files with confirmed critical findings follow the configured remediation policy; - all overwritten content remains recoverable. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (18)

Instruction Override

High
Category
Prompt Injection
Content
- New untracked files

### Prompt Injection Patterns
- **Instruction override** — "ignore previous instructions", "you are now", "forget your instructions"
- **System prompt markers** — `<system>`, `[SYSTEM]`, `<<SYS>>`, `[INST]`
- **Markdown exfiltration** — Image tags with encoded data in URLs
- **Base64 payloads** — Large encoded blobs outside code blocks
Confidence
80% confidence
Finding
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Instruction Override

High
Category
Prompt Injection
Content
- New untracked files

### Prompt Injection Patterns
- **Instruction override** — "ignore previous instructions", "you are now", "forget your instructions"
- **System prompt markers** — `<system>`, `[SYSTEM]`, `<<SYS>>`, `[INST]`
- **Markdown exfiltration** — Image tags with encoded data in URLs
- **Base64 payloads** — Large encoded blobs outside code blocks
Confidence
80% confidence
Finding
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [agent_skills]

High
Category
YARA Match
Content
}
}
```

### OpenClaw (heartbeat)

Add to HEARTBEAT.md:
```
- Run workspace integrity protection
```

### After Installing New Skills

Run `protect` to auto-quarantine skills that modified workspace files.

## What It Detects

### Integrity Violations
- Modified files (SHA-256 checksum comparison)
- Deleted files
- New untracked files

### Prompt Injection Patterns
- **Instruction override** — "ignore previous instructions", "you are now", "forget your instructions"
- **System prompt markers** — `<system>`, `[SYSTEM]`, `<<SYS>>`, `[INST]`
- **Markdown exfiltration** — Image tags with encoded data in URLs
- **Base64 payloads** — Large encoded blobs outside code blocks
- **Unicode manipulation** — Zero-width characters, RTL overrides, homoglyphs
- **HTML injection** — `<script>`, `<iframe>`, hidden elements
- **Shell injection** — `$(...)` subshell execution outside code blocks

## File Categories

| Category | Files | Alert Level |
|----------|-------|-------------|
| Crit
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The manifest markets the skill as a 'full workspace security suite' and emphasizes protection, but the documented behavior includes mutating trust state, writing baseline data into the workspace, and destructive countermeasures whose coverage is narrower than advertised. This mismatch is dangerous because users and agents may grant trust or auto-run the skill assuming comprehensive, defensive behavior when it can also alter the workspace and institutionalize a compromised state via baseline acceptance.

Missing User Warnings

High
Confidence
97% confidence
Finding
The documentation recommends an automated 'protect' action that can restore files and quarantine skills, but it does not clearly warn that these are destructive workspace modifications that may remove legitimate changes or disable installed components. In a security-themed skill, silent auto-remediation is especially risky because users may assume it is always safe and corrective, even when detections are incomplete or mistaken.

Missing User Warnings

High
Confidence
99% confidence
Finding
The recommended SessionStart hook auto-executes remediation every session, enabling unsolicited file restoration and skill quarantine before the user reviews what changed. This is highly dangerous because startup automation amplifies any false positive, poisoned baseline, or adversarial configuration into repeated destructive actions across the workspace, effectively giving the skill persistent authority to rewrite security-sensitive files.

Missing User Warnings

High
Confidence
98% confidence
Finding
The restore command joins a user-supplied path directly with the workspace and copies snapshot content to that destination without verifying that the resolved destination remains inside the workspace. An attacker who can influence the filepath argument or convince an operator to use a traversal path like '../../target' may overwrite arbitrary files writable by the current user, which is especially dangerous in a security tool with destructive repair features.

Missing User Warnings

High
Confidence
94% confidence
Finding
Protect mode automatically restores files and quarantines skills based on pattern matches, without any confirmation gate, dry-run default, or trust boundary checks. In this skill context, that is more dangerous because the tool is positioned as an autonomous security layer; a false positive or manipulated baseline can trigger broad destructive changes to the workspace and disable skills automatically.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The README promotes automated restore, rollback, and quarantine actions but does not clearly warn users that these countermeasures can overwrite legitimate work, disable installed skills, or alter repository state. In a security automation tool, lack of explicit caution increases the chance of unsafe deployment and unintended destructive actions.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The session-start hook configuration causes protective actions to run automatically on every session, yet the README does not warn that this may trigger restoration, rollback, or quarantine without per-run review. Auto-execution at startup makes accidental disruption more likely because the user may not realize state-changing actions are occurring implicitly.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill is explicitly user-invocable and documents shell commands that can read and write workspace files, restore snapshots, rename skill directories, and perform rollback operations, yet it declares no tool scope or allowed-tools constraints. That leaves a powerful, destructive skill under-bounded, increasing the chance an agent invokes filesystem and shell capabilities more broadly than users expect.

Vague Triggers

Medium
Confidence
88% confidence
Finding
The manifest uses broad activation language for a user-invocable skill with shell and file-write capabilities, making it easier for an agent to apply the skill in situations that do not justify destructive remediation. In context, this is more dangerous because the skill presents itself as a general security layer, which can bias users toward trusting broad invocation without understanding the side effects.

Description-Behavior Mismatch

Medium
Confidence
88% confidence
Finding
The accept command updates the manifest hash for a changed file but does not refresh the stored snapshot for categories that are supposed to be restorable. That means a malicious or accidental file change can be accepted into the baseline while restore still points to stale content, undermining the advertised integrity and recovery guarantees and potentially causing inconsistent or unsafe remediation behavior later.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
sys.exit(1)

    # Check if file is tracked by git
    result = subprocess.run(
        ["git", "ls-files", rel],
        cwd=str(workspace),
        capture_output=True, text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The rollback command runs 'git checkout HEAD -- <file>', which discards local changes to the target file. Although the module docstring mentions git rollback, this function itself provides no explicit pre-action warning or confirmation before carrying out an irreversible overwrite of user changes.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
sys.exit(1)

    # Checkout from HEAD
    result = subprocess.run(
        ["git", "checkout", "HEAD", "--", rel],
        cwd=str(workspace),
        capture_output=True, text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Intent-Code Divergence

Medium
Confidence
94% confidence
Finding
The protect workflow claims to quarantine skills containing injections, but the implementation only quarantines when the injected file path matches skills/<name>/SKILL.md. If a malicious skill hides prompt injection in other monitored files or in unmonitored files associated with the skill, the tool may report protection while leaving the skill active, creating a false sense of security in a tool specifically marketed as an automatic defense layer.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
git_dir = workspace / ".git"
            if git_dir.exists():
                import subprocess
                result = subprocess.run(
                    ["git", "checkout", "HEAD", "--", rel],
                    cwd=str(workspace),
                    capture_output=True, text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

Detected: suspicious.prompt_injection_instructions

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
README.md:118