What it detects
Ironheights ships 35 rules. 17 run on skill content during scan, 4 more join scan in the CLI (MCP config files and the advisory feed), 4 come from verify against your baseline, 9 from audit-config, and 1 is an optional model note. The list below is generated from the rule metadata in the public rules document. Each rule has a full write-up in the rules reference.
Rules describe known patterns. A skill that matches none of them can still be harmful. See Limitations.
Content rules
These 17 also run in the in-browser scanner.
| Rule | Severity | What it flags |
|---|---|---|
IH-EXEC-001 | critical | Fetching remote text and passing it straight to a shell or runtime executes attacker-controlled code. Fix: Download to a file, review it, and run a pinned local copy instead of piping a URL into a shell. |
IH-EXEC-002 | high | Skills sometimes tell the agent to install a tool from a URL or git link before doing anything else. Each command is reported once, on the line that contains it. Fix: Install only from the language registry or the operating-system package manager, pinned to a version. |
IH-EXEC-003 | high | eval, the Function constructor, and shell-enabled subprocess calls run strings as code. Fix: Call a fixed function or pass an argument array with shell disabled. |
IH-NET-001 | medium | A skill that contacts a host outside the allowlist can send data somewhere the user did not expect. A download, install, or fetch instruction is a contact, and so is a paste site or a file-drop host. A homepage field, a license URL, a schema link, or an official API host in prose is not a contact. Fix: Declare the host in allowDomains, or in metadata.ironheights.allowDomains for this skill only. Prefer the official API host. |
IH-NET-002 | high | A sensitive read and an outbound request in the same few lines can move credentials off the machine. Telling the agent to send a credential path to a URL counts. Fix: Split credential access from network calls, and do not send secrets to a remote host. |
IH-CRED-001 | high | References to keys, browser stores, wallets, shell history, or OpenClaw auth files expose credentials. A credential directory such as ~/.ssh, ~/.aws, ~/.gnupg, or ~/.azure counts with or without a file name after it. Windows forms count too: ~\.ssh, %USERPROFILE%\.ssh, and AppData paths for Chrome, Firefox, or the credential store. Fix: Do not read these paths from a skill. Use a scoped environment variable or the platform secret store. |
IH-CRED-002 | high | Private keys and live tokens checked into a skill can be copied by anyone who reads the skill. Fix: Remove the secret, rotate it, and load it from the environment or a secret store. |
IH-CRED-003 | medium | Asking the user to paste a secret into chat or memory stores it in the transcript. Fix: Tell the user to set an environment variable or use the secret store, and do not echo the value. |
IH-INJ-001 | high | Phrases that tell the agent to ignore prior rules are a common way to hide malicious steps. Fix: Delete the override text. Treat skill content as untrusted instructions. |
IH-INJ-002 | high | Invisible characters, HTML comments, and huge base64 blobs can hide instructions from a person reading the file. Fix: Remove hidden characters and comments. Keep data files separate from the skill instructions. |
IH-INJ-003 | high | Instructions to disable approvals or edit agent files change the trust boundary of the assistant. Fix: Refuse the change. Agent config and other skills should be edited only by the user. |
IH-OBF-001 | medium | Packed or encoded payloads are used to hide a command from a person reviewing the skill. Fix: Ship readable source. Reject skills that decode or reconstruct commands at runtime. |
IH-PERSIST-001 | high | Scheduled tasks, login hooks, and shell startup files keep code running after the skill is closed. Fix: Remove the persistence step. A skill should not install itself into login or scheduler configuration. |
IH-PRIV-001 | high | sudo, broad chmod, and commands that turn off Gatekeeper or firewall protections weaken the host. Fix: Do not elevate privileges or remove OS protections. Ask the user to install software through the normal path. |
IH-BIN-001 | high | Executables and archives shipped inside a skill can hide an installer. Archives are flagged and never extracted. Fix: Remove the binary. Document a package-manager install instead of bundling an executable or archive. |
IH-FS-001 | medium | Symlinks that leave the skill, path traversal, and hidden files can read or hide data outside the skill. Fix: Keep every file inside the skill directory. Do not use symlinks that point elsewhere or dotfiles to hide content. |
IH-META-001 | low | OpenClaw discovers a skill from SKILL.md frontmatter. Missing fields make the skill harder to identify and review. Fix: Add YAML frontmatter with name and description. The name should match the folder name. |
MCP config and advisory rules (CLI only)
Added in 0.2.0. scan reads MCP configuration files for risky server commands, literal secrets and broad filesystem roots, and reports IH-ADV-001 when a verified advisory feed cache on your machine lists the skill. The browser scanner does not run these. See advisory feed support.
| Rule | Severity | What it flags |
|---|---|---|
| high | An MCP config that starts a server with curl piped into a shell, or with npx of a package that is not pinned to a version, runs code the operator has not reviewed. A shell pipe is critical. A pinned package such as name@1.2.3, a local path, and a local node script are not. Fix: Pin the package to an exact version or a commit, or run a local script. Do not pipe a downloaded script into a shell. | |
IH-MCP-002 | high | A literal secret in an MCP server env block is copied onto disk and into the server process. A reference such as ${API_KEY} is not a literal. Fix: Remove the value and pass the name of an environment variable the operator sets outside the config file. |
IH-MCP-003 | medium | A filesystem MCP server pointed at /, a drive root, or a home directory can read far more than the project. A subdirectory such as ./notes or /home/alex/projects/notes is not a broad root. Fix: Pass a project directory, not a home directory or a filesystem root. |
IH-ADV-001 | critical | The cached signed advisory feed lists this skill name, a file content hash, or an indicator host. The match is reported only when a local cache is present. Scan does not contact the network to refresh the feed. Fix: Do not install or enable this skill. Read the source links, then quarantine the copy if it is already on disk. |
Integrity rules
| Rule | Severity | What it flags |
|---|---|---|
IH-INT-001 | high | A file in an installed skill no longer matches the saved baseline. Fix: Review the diff. Restore the file or create a new baseline only after you accept the change. |
IH-INT-002 | medium | A file or skill directory appeared after the baseline was created. Fix: Inspect the new file before trusting the skill, then update the baseline if you accept it. |
IH-INT-003 | medium | A file that was in the baseline is gone. Fix: Confirm the deletion was intentional. A missing file can also mean the skill was replaced. |
IH-INT-004 | high | An agent instruction, personality, memory, or config file changed since the baseline. Fix: Compare the agent file with a copy you trust before starting the agent again. |
OpenClaw config audit rules
ironheights audit-config reads your local OpenClaw config and reports risky settings. It is offline and read-only, and it does not replace openclaw security audit.
| Rule | Severity | What it flags |
|---|---|---|
IH-CFG-001 | high | gateway.bind is lan, tailnet, custom, auto, or an all-interfaces address, or gateway.tailscale.mode is funnel. OpenClaw's native check gateway.bind_no_auth covers a remote bind without a shared secret, and gateway.tailscale_funnel covers public Funnel. This rule only reads the config value. It does not probe the listener. auto is medium because the effective bind is chosen at runtime. Funnel and 0.0.0.0 are critical. Fix: Prefer gateway.bind "loopback". If the Gateway must leave the machine, require token or password auth and firewall the port. Do not use Tailscale Funnel for a Gateway you have not locked down. Run openclaw security audit for a live check. |
IH-CFG-002 | critical | gateway.auth.mode is none or trusted-proxy, a non-loopback bind has no auth object, or the token or password in the file is empty or a known placeholder. Native checks gateway.bind_no_auth, gateway.loopback_no_auth, gateway.token_placeholder_value, and gateway.trusted_proxy_auth overlap this rule. A loopback bind that omits auth is not flagged: OpenClaw's default is authenticated, and the token may live in OPENCLAW_GATEWAY_TOKEN, which this command does not read. trusted-proxy is critical because the proxy becomes the auth boundary; proxy IPs and headers are left to the native audit. Fix: Set gateway.auth.mode to token or password and store the secret in the environment or a SecretRef, not as a placeholder. For trusted-proxy, run openclaw security audit and keep gateway.trustedProxies tight. This command never prints the secret. |
IH-CFG-003 | critical | A channel dmPolicy (or dm.policy) is open, so anyone can DM the agent. This matches the native check channels.<channel>.dm.open. Mutable allowFrom entries and name matching are not reimplemented. Fix: Set dmPolicy to pairing or allowlist. Open is a last resort in the OpenClaw docs. Run openclaw security audit before exposing a bot. |
IH-CFG-004 | high | A channel groupPolicy is open, so any member of a group can talk to the agent. Severity rises to critical when the same config also enables host exec, elevated tools, or an open DM policy. Native security.exposure.open_groups_with_elevated and security.exposure.open_channels_with_exec cover the live combination; this rule only reads the file. Fix: Set groupPolicy to allowlist and require mentions. Do not combine an open room with tools.exec.security full or tools.elevated. |
IH-CFG-005 | high | A token, password, secret, or API key is a literal string in the config file. ${ENV} references and SecretRef objects (source env, file, exec, or store) are not literals. Placeholder literals are reported as IH-CFG-002 instead. Evidence is the key path plus <redacted>. Native config.secrets.gateway_password_in_config and config.secrets.hooks_token_in_config are the overlapping checks; other secret keys in the file are reported here too. Fix: Remove the literal. Use a SecretRef or an environment variable. Rotate the value if the file was copied or committed. This command does not print the value. |
IH-CFG-006 | critical | On POSIX, the config file is group-writable, world-writable, world-readable, or group-readable. A symlink is reported at medium severity because OpenClaw documents that a symlinked openclaw.json is unsupported. Native checks fs.config.perms_world_readable, fs.config.perms_writable, fs.config.perms_group_readable, and fs.config.symlink. Windows ACLs are not Unix mode bits. This rule does not report permission findings on Windows and does not run icacls. OpenClaw's audit does. Fix: On POSIX, chmod 600 the config file and do not symlink it. On Windows, run openclaw security audit so ACL resets can be reviewed. This command never changes permissions. |
IH-CFG-007 | high | tools.exec.security or an agent exec security is full, exec ask is off while security is not deny, or tools.elevated is enabled. Elevated allowFrom containing * is critical. Native tools.exec.security_full_configured and tools.elevated.allowFrom.<channel>.wildcard overlap this rule. Interpreter allowlists, safeBins, and approval-file drift are left to the native audit. Fix: Set tools.exec.security to deny or allowlist, set tools.exec.ask to always, and keep tools.elevated.enabled false unless allowFrom is a named list without *. |
IH-CFG-008 | medium | skills.load.extraDirs or skills.load.allowSymlinkTargets is set. Extra directories are the lowest-precedence skill roots and are trusted by the operator. OpenClaw tells you to keep allowSymlinkTargets narrow. A home directory, a filesystem root, or a path that contains .. is critical. Other extra directories are medium. The native audit does not have this check; it does have skills.workspace.symlink_escape, which walks the workspace and is not repeated here. Fix: Remove extra directories you do not trust. Do not point extraDirs or allowSymlinkTargets at ~, /, or a drive root. Scan those directories with ironheights scan before loading them. |
IH-CFG-009 | medium | Sandbox mode is off, or sandbox.docker is set while mode is off, and the file also enables host exec, elevated tools, or an open room. A personal agent with sandbox off and tools.exec.security deny is a documented OpenClaw pattern and stays quiet. Native sandbox.docker_config_mode_off and the security.exposure.open_groups_with_runtime_or_fs checks overlap the noisy cases. Docker bind mounts, seccomp, and AppArmor are not reimplemented. Fix: Set agents.defaults.sandbox.mode to all for any agent that can exec or that strangers can message. Otherwise set tools.exec.security to deny. Run openclaw security audit for sandbox mount checks. |
Optional model note
IH-LLM-001 appears only when you ask for a model second opinion. It never changes the verdict, the grade or the exit code.
| Rule | Severity | What it flags |
|---|---|---|
IH-LLM-001 | info | An optional language-model review added a note. This is not a pattern rule and it does not scan files by itself. The model sees redacted skill text and the deterministic findings, and it can be wrong. The note never changes the verdict or the exit code. It appears only after `scan --llm` or `review`, and only when the model output matched the review schema. Fix: This note is advisory and can be wrong. It does not change the deterministic verdict. Confirm it yourself before you act on it. |
How secrets are reported
IH-CRED-002 uses Shannon entropy: a quoted value assigned to a key-like name is reported when it is at least 20 characters and at least 4 bits per character. Evidence keeps the first four characters and masks the rest, so reports do not leak the secret again.
Allowlisted hosts
An allowlist entry matches a host and its subdomains. The built-in list includes example domains, localhost, GitHub, npm, PyPI, and openclaw.ai. Add your own with allowDomains.