You can ship an OpenClaw agent in 60 seconds, but a security incident lasts forever. This guide documents a hands-on process for auditing third-party or in-house OpenClaw skills before they reach production. Everything here is based on real audits we ran on v3.8.1 of the framework and dozens of skills in the wild.
Why auditing OpenClaw skills matters
OpenClaw agents run under Node 22+, with browser control, shell access, scheduled tasks, and over 800 integrations via Composio. A single malicious skill.js can exfiltrate tokens, fork bomb the host, or spam a Slack workspace faster than you can say “npm audit”. Unlike a classic NPM package, a skill executes in the context of an already-privileged agent that you or your users trust. Treat it more like a browser extension audit than a dependency bump.
Establishing a repeatable audit pipeline
Ad-hoc reviews do not scale. The pipeline below fits in any CI runner (we use GitHub Actions) and surfaces 80 % of issues before a human even looks at code.
- Static lint pass (
eslint@9, custom OpenClaw rules) - Automated pattern scan (Semgrep, 63 rules we’ll share)
- Manual SKILL.md review (red flags in documentation)
- Scoped runtime test in --sandbox mode
- Outbound traffic diff against “known-good” baseline
- Post-merge dynamic scan inside staging agent
The rest of this article walks through each step.
Step 1: Inspect the SKILL.md for red flags
Every skill is required by convention (not by the runtime) to ship a SKILL.md that describes:
- Purpose and intent
- Required environment variables / secrets
- Permissions needed (shell, browser, memory)
- External services contacted
Things we look for immediately:
- Over-broad claims. “Needs full disk access” even though it just resizes images.
- Missing auth flow clarity. If the skill posts to GitHub, does it ask for
reposcope orrepo, admin:org? The latter is rarely necessary. - Opaque update policy. If the author auto-updates via
curl | bash, stop reading and reject the PR.
Tip: wire a grep job that fails CI when SKILL.md contains “curl” and “sudo” on the same line.
Step 2: Map every outbound request
Most data leaks hide in HTTP calls. We run a two-phase approach:
Static mapping
A Semgrep rule catches patterns like:
axios.post(/https?:\/\/[^"]+/, ...)
and annotates the file. We dump unique domains into outbound_static.txt for later diff.
Dynamic mapping
Spin up the skill in sandbox:
npx openclaw run --skills ./third_party/image-resize --sandbox
Then monitor network:
mitmproxy --mode transparent --set block_global=false --listen-port 8080
Compare domains observed at runtime (outbound_dynamic.txt) with the static set. Any delta needs human eyes.
Edge case: skills that rely on websocket or gRPC. Add tcpdump capture to pick those up:
sudo tcpdump -i any -w skill.pcap host not 127.0.0.1
Step 3: Verify file system and shell scope
OpenClaw exposes a helper in the agent context:
ctx.exec("ls -la /home/openclaw")
This is powerful and abusable. Questions we ask:
- Does the skill write outside
ctx.paths.temp? - Does it read user memory (hosted under
~/.openclaw/memory) without explicit intent? - Does it spawn nested shells (
/bin/sh -cinside Bash)? That often indicates obfuscation.
Simple grep:
grep -R "exec(" third_party/image-resize | grep -v "ctx.exec('convert'"
CI fails on hits.
If the skill needs shell for legitimate image processing, we pin to a whitelist:
"allowedCommands": ["convert", "identify"]
and load a patched runtime guard:
OPENCLAW_ALLOWED_CMDS=$(cat allowed.json) npx openclaw run --sandbox
Step 4: Contain the skill in sandbox mode first
OpenClaw v3.7 introduced --sandbox. Under the hood it spawns the skill in a child process with:
- Read-only FS except
/tmp/openclaw-sandbox-* - Network egress blocked except domains defined in
skill.json - No access to persistent memory
Enabling it is one flag:
npx openclaw run --skills ./third_party/image-resize --sandbox
Watch for runtime errors. If the skill crashes because it cannot write to /home/openclaw, that’s a bug in the skill, not the sandbox. Fix or reject.
We keep sandbox mode enabled in production for 90 % of skills. The 10 % outliers are typically internal DevOps helpers that need shell access.
Step 5: Automate with static and dynamic scanners
Static scan: Semgrep
Create .semgrep/openclaw.yml:
rules:
- id: no-hardcoded-keys
patterns:
- pattern: "${KEY}"
message: "Hard-coded key found"
severity: ERROR
- id: dangerous-child-process
patterns:
- pattern: child_process.exec($CMD)
message: "Unvetted exec call"
severity: WARNING
Run in CI:
semgrep --config=.semgrep --json | tee semgrep.json
Fail the build on any ERROR.
Dynamic scan: OClawSec
The community published a small wrapper “OClawSec” (MIT license) that pipes the agent through node --inspect, watches syscalls, and generates a SARIF report. Install:
npm i -g oclawsec
Then:
oclawsec scan --skill ./third_party/image-resize --timeout 120
Common findings:
- Temp file not deleted after run
- Unexpected DNS lookup (
geo.ipify.orgused for tracking) - Telemetry pings back to author’s server
Step 6: Document, patch, and upstream fixes
Auditing without remediation is just academic. We follow GitHub’s security advisory flow:
- Open
SECURITY.mdissue in private fork, include PoC and logs - Offer patch PR, require maintainer sign-off
- Release patched version tagged
vX.Y.Z-secure - Archive CVE via GitHub Advisory Database if severity >= 7.0 CVSS
For internal skills, the checklist lives in a Notion page linked from each repo. Failures block deploy in ClawCloud via our Slackbot (/claw approve deploy-43 rejects if audit-status ≠ “pass”).
Checklist: questions to ask before deploying to production
- Does
SKILL.mdlist every environment variable it reads? - Did static scan find any hard-coded secrets?
- Do dynamic network logs match the doc?
- Is sandbox mode enabled in production?
- Are shell commands whitelisted?
- Have we fuzz-tested inputs for command injection?
- Is the skill pinned to a commit hash, not
main? - Do we have alerts for abnormal memory or CPU spikes?
If the answer to any question is “no”, the deploy waits.
Resources and next steps
- OpenClaw Security Guide v3.8.1 (docs folder in the repo)
- Sample Semgrep ruleset:
github.com/clawcloud/sec-rules oclawsecdynamic scanner:npmjs.com/package/oclawsec- Community thread: “How we sandboxed 150 skills” (#4287)
Auditing is never “done”, but the process above compresses it into a checklist that fits any engineering sprint. Wire it into CI today, enable --sandbox by default, and ship skills without losing sleep.