Back to skill

Security audit

claw-security-audit

Security checks for vulnerabilities and agentic risk

Overview

This skill performs a disclosed local security audit, with sensitive-file access appropriate to its purpose and optional private reports.

Choose scan roots and the Git repository deliberately. Keep reports private, or use --no-report to avoid saving them. The concerning scanner matches resolve to disclosed audit behavior and detection examples. Full source inspection addressed its partial coverage warning; audit results remain heuristic and cannot guarantee security.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (17)

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · CHANGELOG.md (reported line 21)May include surrounding context.

md
### Changed
- Standard library only; `requests`, `rich`, `jsonschema`, `pyyaml` no longer needed. Python 3.8+.
- Supply-chain scan covers several skill folders and SKILL.md `curl | sh` patterns.

## [1.0.0] - 2026-10-31
- Initial version.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 48)May include surrounding context.

md
| ID | Check | Severity | What it looks for |
|----|-------|----------|-------------------|
| SEC001 | Secrets in config files | critical | Plain-text keys, tokens and passwords in `openclaw.json` and agent configs |
| SEC002 | Secrets in .env files | high | Keys stored in `.env` files under `env_scan_roots` |
| SEC003 | Secrets in git history | critical | Known key formats added in the last 50 commits |
| CFG001 | Gateway config review | high | Gateway reachable from the network, auth off, DMs open to anyone, `*` allowlists, exec with no approvals |
| PERM001 | Sensitive file permissions | medium | Config, `.env` and state files readable by other users (ACLs on Windows, mode bits elsewhere) |

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · README.md (reported line 54)May include surrounding context.

md
| PERM001 | Sensitive file permissions | medium | Config, `.env` and state files readable by other users (ACLs on Windows, mode bits elsewhere) |
| NET001 | Network exposure | high | Debugging/admin ports (9222, 18789, 18800, 11434, ...) listening on all interfaces; tunnels such as ngrok |
| CRYPTO001 | Crypto hygiene | medium | Unencrypted private keys in the OpenClaw folder, TLS verification turned off |
| SUPPLY001 | Supply chain | medium | Skills shipping binaries, npm install hooks that download code, `curl \| sh` instructions |
| SESSION001 | Session hygiene | low (info) | Very large state databases, logs older than 30 days |

The checks are heuristics. A PASS means nothing obvious was found, not that the system is guaranteed secure. Built-in OpenClaw diagnostics (for example `openclaw security audit`, where available) complement this tool.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · audit.py (reported line 304)May include surrounding context.

python
def check_env_files(self) -> Dict[str, Any]:
        findings, files = [], 0
        for root in self.config.get("env_scan_roots", []):
            for f in self._walk(self._p(root), lambda n: n == ".env" or n.startswith(".env.") or n.endswith(".env")):
                if f.name.endswith((".example", ".sample", ".template")):
                    continue
                text = self._read_text(f)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · audit.py (reported line 304)May include surrounding context.

python
def check_env_files(self) -> Dict[str, Any]:
        findings, files = [], 0
        for root in self.config.get("env_scan_roots", []):
            for f in self._walk(self._p(root), lambda n: n == ".env" or n.startswith(".env.") or n.endswith(".env")):
                if f.name.endswith((".example", ".sample", ".template")):
                    continue
                text = self._read_text(f)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · audit.py (reported line 322)May include surrounding context.

python
findings.append({"file": self._show(f), "line": i, "key": key, "length": len(val)})
        if findings:
            return {"status": "warning",
                    "message": f"{len(findings)} secret(s) stored in {files} .env file(s) (values hidden)",
                    "details": {"findings": findings[:50]},
                    "remediation": "Keep .env files out of git (.gitignore), restrict them to your user account, "
                                   "and never include them in skill packages or backups you share."}

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · audit.py (reported line 324)May include surrounding context.

python
return {"status": "warning",
                    "message": f"{len(findings)} secret(s) stored in {files} .env file(s) (values hidden)",
                    "details": {"findings": findings[:50]},
                    "remediation": "Keep .env files out of git (.gitignore), restrict them to your user account, "
                                   "and never include them in skill packages or backups you share."}
        return {"status": "pass", "message": f"No plain-text secrets found in {files} .env file(s)", "details": {}}

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · audit.py (reported line 326)May include surrounding context.

python
"details": {"findings": findings[:50]},
                    "remediation": "Keep .env files out of git (.gitignore), restrict them to your user account, "
                                   "and never include them in skill packages or backups you share."}
        return {"status": "pass", "message": f"No plain-text secrets found in {files} .env file(s)", "details": {}}

    def check_git_history_secrets(self) -> Dict[str, Any]:
        repo = self.config.get("git_repo") or os.getcwd()

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · audit.py (reported line 577)May include surrounding context.

python
CHECKS = [
        ("SEC001", "Secrets in Config Files", "secrets", "critical", "check_secrets_in_config"),
        ("SEC002", "Secrets in .env Files", "secrets", "high", "check_env_files"),
        ("SEC003", "Secrets in Git History", "secrets", "critical", "check_git_history_secrets"),
        ("CFG001", "Gateway Config Review", "config", "high", "check_config_validation"),
        ("PERM001", "Sensitive File Permissions", "permissions", "medium", "check_file_permissions"),

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · audit.py (reported line 350)May include surrounding context.

python
if findings:
            return {"status": "fail", "message": f"{len(findings)} secret(s) added in the last 50 commits (values hidden)",
                    "details": {"findings": findings[:50]},
                    "remediation": "Rotate the exposed credentials first, then purge history with git-filter-repo or BFG."}
        return {"status": "pass", "message": "No known secret formats in the last 50 commits"}

    def _load_gateway_config(self) -> Optional[Dict[str, Any]]:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · audit.py (reported line 407)May include surrounding context.

python
paths = self.config["openclaw_paths"]
        out = [self._p(paths["gateway_config"])]
        for root in self.config.get("env_scan_roots", []):
            out += list(self._walk(self._p(root), lambda n: n == ".env" or n.startswith(".env.")))
        state = self._p(paths["state_dir"])
        if state.is_dir():
            out += [p for p in state.iterdir() if p.is_file() and p.suffix in (".sqlite", ".json", ".db")]

Autonomous Decision Making

Medium
Category
Excessive Agency
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.

Content

Scanner excerpt · CHANGELOG.md (reported line 16)May include surrounding context.

md
- CRYPTO001: bounded, error-tolerant walker; long Windows paths, junction loops and `node_modules` no longer crash it. Removed substring check that matched "des" in "description".
- SEC003: scans added lines in the last 50 commits instead of `--stat` output; `--git-repo` option.
- NET001: runs netstat once, separates ports exposed on all interfaces from loopback-only; tunnel detection works on Windows.
- CFG001: replaced false-positive "missing config" warning with real OpenClaw risk checks (bind, auth, open DMs, wildcard allowlists, exec without approvals).
- `--check` now runs only the requested check; config toggles in `checks` actually disable checks; `info` status counted.

### Changed

Autonomous Decision Making

Medium
Category
Excessive Agency
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.

Content

Scanner excerpt · README.md (reported line 50)May include surrounding context.

md
| SEC001 | Secrets in config files | critical | Plain-text keys, tokens and passwords in `openclaw.json` and agent configs |
| SEC002 | Secrets in .env files | high | Keys stored in `.env` files under `env_scan_roots` |
| SEC003 | Secrets in git history | critical | Known key formats added in the last 50 commits |
| CFG001 | Gateway config review | high | Gateway reachable from the network, auth off, DMs open to anyone, `*` allowlists, exec with no approvals |
| PERM001 | Sensitive file permissions | medium | Config, `.env` and state files readable by other users (ACLs on Windows, mode bits elsewhere) |
| NET001 | Network exposure | high | Debugging/admin ports (9222, 18789, 18800, 11434, ...) listening on all interfaces; tunnels such as ngrok |
| CRYPTO001 | Crypto hygiene | medium | Unencrypted private keys in the OpenClaw folder, TLS verification turned off |

Autonomous Decision Making

Medium
Category
Excessive Agency
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.

Content

Scanner excerpt · audit.py (reported line 386)May include surrounding context.

python
tools = cfg.get("tools") if isinstance(cfg.get("tools"), dict) else {}
        exec_cfg = tools.get("exec") if isinstance(tools.get("exec"), dict) else {}
        if str(exec_cfg.get("security", "")).lower() == "full" and str(exec_cfg.get("ask", "")).lower() == "off":
            issues.append("Shell exec runs with full access and no approval prompts")
        channels = cfg.get("channels") if isinstance(cfg.get("channels"), dict) else {}
        for name, ch in channels.items():
            if not isinstance(ch, dict) or ch.get("enabled") is False:

Skill declares no tool scope ('permissions' or 'allowed-tools') but code capabilities were detected: file_read, file_write, network, shell.

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · audit.py (reported line 133)May include surrounding context.

python
if not shutil.which(cmd[0]):
        return None
    try:
        return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout, cwd=cwd,
                              encoding="utf-8", errors="replace")
    except (OSError, subprocess.SubprocessError):
        return None

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · audit.py (reported line 592)May include surrounding context.

python
if only and cid not in only:
                continue
            print(f"  Checking {cid} {name}...", file=sys.stderr)
            self._add(cid, name, cat, sev, getattr(self, fn))
        count = lambda s: sum(1 for r in self.results if r.status == s)
        return AuditReport(__version__, datetime.now().isoformat(timespec="seconds"), self._openclaw_version(),
                           sys.platform, sys.version.split()[0], len(self.results), count("pass"), count("fail"),