Back to skill

Security audit

Audit OpenClaw Security

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent defensive OpenClaw audit skill, but its bundled redaction and audit-collection helpers can expose sensitive data if users trust their outputs too much.

Install only if you are comfortable reviewing the generated audit folder and redacted config output before sharing. Do not treat the bundled redactor as sufficient for secrets; manually verify or remove credential values, especially short passwords, tokens, cookies, and API keys. Store collector output in a private directory because it may reveal network, firewall, plugin, and OpenClaw posture details.

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

Error
Location
scripts/redact_openclaw_config.py:37
Finding
Sensitive-key values shorter than 24 characters bypass redaction<![CDATA[ ## Vulnerability Details **File Location**: `scripts/redact_openclaw_config.py`, lines 37–73 **Vulnerability Type**: Incomplete credential redaction **Risk Level**: High ### Vulnerable Code ```python def mask(s: str) -> str: s = s or "" if len(s) <= 8: return "***" return f"{s[:4]}…{s[-4:]}" def looks_secret(s: str) -> bool: if len(s) < 24: return False if s.startswith(("http://", "https://", "/", "./", "../", "~/")): return False return bool(JWT_LIKE_RE.match(s) or HEXISH_RE.match(s) or ALNUMISH_RE.match(s)) def redact_string(s: str) -> str: if looks_secret(s): return mask(s) return URL_QS_SECRET_RE.sub(lambda m: m.group("prefix") + mask(m.group("val")), s) def redact_obj(obj: Any) -> Any: if isinstance(obj, dict): out: dict[str, Any] = {} for key, value in obj.items(): skey = str(key) if SENSITIVE_KEY_RE.search(skey): if isinstance(value, str): out[skey] = redact_string(value) else: out[skey] = "***" else: out[skey] = redact_obj(value) return out ``` ### Technical Analysis When a key matches `SENSITIVE_KEY_RE`, its string value is passed to `redact_string()` rather than being unconditionally replaced. `redact_string()` only masks a standalone value if `looks_secret()` recognizes it as secret-like. The first condition in `looks_secret()` rejects every value shorter than 24 characters. Consequently, short passwords, API keys, session keys, cookies, and tokens remain unchanged unless they happen to appear as a recognized URL query parameter. This violates the script's documented security purpose: users are instructed to run it before sharing a configuration file and may reasonably treat its output as safe. The issue affects structured JSON and JSON5 processing. Retaining four-character prefixes and suffixes for longer credentials ...[truncated 1443 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Unconditionally replace every value associated with a sensitive key: ```python if SENSITIVE_KEY_RE.search(skey): out[skey] = "***" ``` 2. Do not preserve prefixes or suffixes of credentials. Partial credential disclosure provides little diagnostic value and may facilitate identification or brute-force attacks. 3. Apply the same unconditional policy in the raw-text fallback. A key classified as sensitive must have its value removed regardless of length, alphabet, or quoting style. 4. Expand handling to cover short bare values, numeric credentials, arrays, multiline strings, and unusual JSON5 syntax. 5. Add automated tests for: - Short passwords and tokens. - Nested sensitive keys. - Sensitive values in lists. - Numeric and Boolean values under sensitive keys. - JSON and JSON5 input. - URL query credentials. - Raw-text fallback behavior. 6. Emit a prominent warning when parsing fails and fallback redaction is used. 7. Continue instructing users to review output manually, but do not treat manual review as a substitute for deterministic redaction. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/collect_openclaw_audit.sh:45
Finding
Audit artifacts inherit potentially permissive filesystem permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/collect_openclaw_audit.sh`, lines 45–64 **Vulnerability Type**: Insecure storage of security-sensitive audit data **Risk Level**: Medium ### Vulnerable Code ```bash TS="$(date -u +"%Y%m%dT%H%M%SZ")" ROOT="${OUT_DIR%/}/openclaw-audit-${TS}" mkdir -p "${ROOT}" log() { echo "[collect] $*"; } write_note() { local name="$1"; shift printf '%s ' "$*" > "${ROOT}/${name}.txt" } run_cmd() { local name="$1"; shift local file="${ROOT}/${name}.txt" log "Running: $*" { echo "$ $*" "$@" } > "${file}" 2>&1 || { echo "[warn] command failed (continuing): $*" >> "${file}" return 0 } } ``` ### Technical Analysis The collector creates its output directory and files without setting a restrictive `umask` or explicitly applying secure permission modes. Their permissions therefore depend on the invoking process's environment. With a common `umask` of `022`, the directory can be created as mode `0755` and files as mode `0644`, making collected artifacts readable by other local users. The output includes host identity, network listeners, firewall rules, container information, OpenClaw configuration values, plugin and skill inventories, state-directory metadata, and security-audit findings. The script does not intentionally copy credential-file contents, but the collected information remains security-sensitive and may reveal enough deployment detail to support targeted attacks. ### Attack Path 1. An operator runs the collector on a multi-user system with a permissive `umask`, such as `022`. 2. The collector creates the timestamped audit directory and files using inherited default permissions. 3. Another local user enumerates the operator's accessible audit output directory. 4. That user reads the generated `.txt` files. 5. The user obtains information about exposed ports, firewall policy, Gateway configuration, authentication mode, enabled tools, plugins, containers, and known security ...[truncated 931 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Set a restrictive process umask before creating any output: ```bash umask 077 ``` 2. Explicitly enforce private directory permissions: ```bash mkdir -p -- "${ROOT}" chmod 700 -- "${ROOT}" ``` 3. Create output files with mode `0600`, or verify and correct permissions immediately after creation. 4. Validate that the chosen output path is not a symlink and is owned by the invoking user before writing audit data. 5. Warn or fail if the output parent directory is writable by untrusted users. 6. Document that audit artifacts contain sensitive operational metadata and must be reviewed before sharing. 7. Provide retention and secure-deletion guidance for generated artifacts. 8. Add tests that run the collector under permissive umasks and verify that directories remain `0700` and files remain `0600`. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (32)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared purpose describes a broad OpenClaw security review and hardening skill. The actual code chunk only implements config redaction: it loads a file or stdin, attempts JSON/JSON5 parsing, masks sensitive keys and secret-looking values, and outputs redacted content. While this is security-adjacent and could support safe sharing during an audit, it is not the declared primary function and introduces an undeclared concrete capability (sanitizing config files). There is no logic for reviewing gateway exposure, auth, access controls, plugins, sandboxing, logs, deployment posture, or interpreting `openclaw security audit` output. Therefore the description does not accurately represent what this code chunk actually does.

Credential Access

High
Category
Privilege Escalation
Content
Audit and discuss these paths carefully without asking for raw contents:

- `~/.openclaw/openclaw.json`
- `~/.openclaw/secrets.json`
- `~/.openclaw/agents/<agentId>/agent/auth-profiles.json`
- `~/.openclaw/agents/<agentId>/sessions/*.jsonl`
- `/tmp/openclaw/openclaw-YYYY-MM-DD.log`
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

YARA rule 'exploit_framework': Exploit framework components and payloads [hacktools]

High
Category
YARA Match
Content
nnels
- [ ] Gateway is not reachable from untrusted networks
- [ ] DM pairing/allowlists are in place
- [ ] Group mention gating is enabled where required
- [ ] File permissions are tightened for OpenClaw state and config
- [ ] Tools are limited to what is actually required

## Residual risk notes

Even a well-hardened agent that can read messages and call tools still carries prompt-injection and social-engineering risk. Record which surfaces remain intentionally open, which tools remain enabled, and how recovery works if the Gateway host or credentials are compromised.
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

YARA rule 'exploit_framework': Exploit framework components and payloads [hacktools]

High
Category
YARA Match
Content
nnels
- [ ] Gateway is not reachable from untrusted networks
- [ ] DM pairing/allowlists are in place
- [ ] Group mention gating is enabled where required
- [ ] File permissions are tightened for OpenClaw state and config
- [ ] Tools are limited to what is actually required

## Residual risk notes

Even a well-hardened agent that can read messages and call tools still carries prompt-injection and social-engineering risk. Record which surfaces remain intentionally open, which tools remain enabled, and how recovery works if the Gateway host or credentials are compromised.
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Privileged Kubernetes Workload

High
Category
Tool Misuse
Content
- keep host-side permissions on the mounted state dir restrictive

4. **Container privileges**
   - avoid `privileged: true`
   - avoid `network_mode: host`
   - avoid unnecessary capabilities
   - run as a non-root user where practical
Confidence
70% confidence
Finding
Code deploys a privileged Kubernetes workload (privileged container, hostPath mount, or host namespaces). This grants root on the node and is a node/cluster takeover vector.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Session Persistence

Medium
Category
Rogue Agent
Content
- `openclaw security audit --json`
   - `openclaw security audit --deep --json`
4. Treat the **Gateway**, **Control UI**, **browser control**, **paired nodes**, and **automation surfaces** as operator-level access.
5. Default to **audit-only**. Before any config edits, `--fix` operations, firewall changes, or restarts, create a backup first and get explicit user approval.
6. When the user wants remediation, make the backup step explicit:
   - `openclaw backup create --verify`
   - use `--no-include-workspace` if the config is invalid but you still need state + creds
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.

Session Persistence

Medium
Category
Rogue Agent
Content
- Paired nodes are remote execution surfaces. Audit them like you would audit operator access.
- Browser control is not “just viewing pages”; it is effectively remote operator capability.
- `gateway` / `cron` tools create persistence and should not be reachable from untrusted chat surfaces.

### 7) Secrets, logs, transcripts, and writable paths
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.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### 7) Secrets, logs, transcripts, and writable paths

Audit and discuss these paths carefully without asking for raw contents:

- `~/.openclaw/openclaw.json`
- `~/.openclaw/secrets.json`
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.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
{
  "fs.state_dir.perms_world_writable": {
    "severity": "critical",
    "category": "filesystem",
    "why": "Other users or processes can modify the full OpenClaw state directory.",
Confidence
70% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
{
  "fs.state_dir.perms_world_writable": {
    "severity": "critical",
    "category": "filesystem",
    "why": "Other users or processes can modify the full OpenClaw state directory.",
Confidence
70% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Session Persistence

Medium
Category
Rogue Agent
Content
Back up first:

```bash
openclaw backup create --verify
```

If the config is invalid but you still want a safety copy:
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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
ss -ltnp
sudo ufw status verbose || true
sudo nft list ruleset || true
sudo iptables -S || true
```
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
```bash
ss -ltnp
sudo ufw status verbose || true
sudo nft list ruleset || true
sudo iptables -S || true
```
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
```bash
ss -ltnp
sudo ufw status verbose || true
sudo nft list ruleset || true
sudo iptables -S || true
```
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
```bash
ss -ltnp
sudo ufw status verbose || true
sudo nft list ruleset || true
sudo iptables -S || true
```
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
```bash
ss -ltnp
sudo ufw status verbose || true
sudo nft list ruleset || true
sudo iptables -S || true
```
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
```bash
ss -ltnp
sudo ufw status verbose || true
sudo nft list ruleset || true
sudo iptables -S || true
```
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
|---|---|---|---|---:|
| `fs.state_dir.perms_world_writable` | Critical | Other users/processes can modify the full OpenClaw state directory. | filesystem perms on `~/.openclaw` | Yes |
| `fs.config.perms_writable` | Critical | Others can change auth, tool policy, and routing config. | perms on `~/.openclaw/openclaw.json` | Yes |
| `fs.config.perms_world_readable` | Critical | The config can leak tokens or security-sensitive settings. | perms on config file | Yes |
| `gateway.bind_no_auth` | Critical | Remote bind without shared secret. | `gateway.bind`, `gateway.auth.*` | No |
| `gateway.loopback_no_auth` | Critical | Reverse-proxied loopback can become unauthenticated. | `gateway.auth.*`, proxy setup | No |
| `gateway.http.no_auth` | Warn/Critical | HTTP endpoints are reachable with `auth.mode="none"`. | `gateway.auth.mode`, `gateway.http.endpoints.*` | No |
Confidence
70% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
|---|---|---|---|---:|
| `fs.state_dir.perms_world_writable` | Critical | Other users/processes can modify the full OpenClaw state directory. | filesystem perms on `~/.openclaw` | Yes |
| `fs.config.perms_writable` | Critical | Others can change auth, tool policy, and routing config. | perms on `~/.openclaw/openclaw.json` | Yes |
| `fs.config.perms_world_readable` | Critical | The config can leak tokens or security-sensitive settings. | perms on config file | Yes |
| `gateway.bind_no_auth` | Critical | Remote bind without shared secret. | `gateway.bind`, `gateway.auth.*` | No |
| `gateway.loopback_no_auth` | Critical | Reverse-proxied loopback can become unauthenticated. | `gateway.auth.*`, proxy setup | No |
| `gateway.http.no_auth` | Warn/Critical | HTTP endpoints are reachable with `auth.mode="none"`. | `gateway.auth.mode`, `gateway.http.endpoints.*` | No |
Confidence
70% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
run_cmd_maybe_sudo() {
  local name="$1"; shift
  local file="${ROOT}/${name}.txt"
  if command -v sudo >/dev/null 2>&1; then
    log "Running (sudo -n): $*"
    {
      echo "$ sudo -n $*"
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
run_cmd_maybe_sudo() {
  local name="$1"; shift
  local file="${ROOT}/${name}.txt"
  if command -v sudo >/dev/null 2>&1; then
    log "Running (sudo -n): $*"
    {
      echo "$ sudo -n $*"
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
run_cmd_maybe_sudo() {
  local name="$1"; shift
  local file="${ROOT}/${name}.txt"
  if command -v sudo >/dev/null 2>&1; then
    log "Running (sudo -n): $*"
    {
      echo "$ sudo -n $*"
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
run_cmd_maybe_sudo() {
  local name="$1"; shift
  local file="${ROOT}/${name}.txt"
  if command -v sudo >/dev/null 2>&1; then
    log "Running (sudo -n): $*"
    {
      echo "$ sudo -n $*"
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
run_cmd_maybe_sudo() {
  local name="$1"; shift
  local file="${ROOT}/${name}.txt"
  if command -v sudo >/dev/null 2>&1; then
    log "Running (sudo -n): $*"
    {
      echo "$ sudo -n $*"
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Static analysis

No suspicious patterns detected.