| name | release-malware-audit |
| description | Release-gate scan for deliberately planted malicious code (crypto miners, data/secret exfiltration, backdoors, RCE/obfuscation, install hooks) across the whole working tree of World of ClaudeCraft. Use before tagging or shipping a release, or whenever you want to confirm the tree is free of malicious code. Runs the deterministic scanner, fans the read-only release-malware-audit agent across categories, and returns a single PASS / BLOCK verdict with confirmed findings and dismissed false positives. Distinct from privacy-security-review, which catches accidental security mistakes. |
| user-invocable | true |
Release malware audit: whole-tree check for planted malicious code
This is a release gate. Its one job is to answer: does this tree contain code that was
deliberately written to harm users, operators, or the supply chain? Crypto miners,
data/secret exfiltration, backdoors and auth bypasses, RCE/obfuscation, web3 wallet-drain /
key theft (the class that would steal a user's $WOC), prompt-injection planted in the
agent/skill instruction files, and package.json install hooks or risky dependencies. It
does NOT look for accidental security bugs - that is privacy-security-review's job - and it
never modifies code. A human acts on a BLOCK.
The work is split so each half does what it is good at:
scripts/malware_scan.mjs is a deterministic, high-recall FLAGGER. It greps a curated
signature catalog and emits structured findings. It is deliberately noisy: a regex hit is
a question, not a verdict.
- The
release-malware-audit agent is the JUDGE. It reads the flagged code in context,
knows this repo's legitimate patterns (the $WOC crypto-wallet, child_process in build
scripts, real auth comparisons), and decides real-vs-false-positive.
Steps
-
Run the scanner over the whole tree:
mkdir -p tmp && node scripts/malware_scan.mjs --json --quiet > tmp/malware_scan.json
It exits non-zero whenever there are findings (expected; most are false positives). Note
totalFindings and the per-category counts. A scan-failure exit (2) means fix the run
before trusting any result - never report PASS off a scan that did not complete.
npm run security:scan is the same human-readable flagger. CI and npm run security:gate
run --gate, which exits non-zero only on a HIGH-severity finding that survives the
path-aware priors (tests/malware_scan.test.ts asserts the tree is HIGH-clean, so a planted
signature breaks npm test). This skill is the deeper, agent-judged pass on top of that.
-
Triage by fanning out the agent. Group the findings by category. Dispatch the
read-only release-malware-audit agent, one invocation per category that has findings
(categories are independent, so run them in parallel in a single message). Give each
agent its category's findings (or point it at tmp/malware_scan.json and the category)
and have it read the flagged files and return confirmed-vs-dismissed for that category.
For a small number of total findings, a single agent invocation over all of them is fine.
-
Synthesize one verdict. Combine the agents' results into a single report:
- PASS only if every flag is explained by legitimate behavior.
- BLOCK if there is even one confirmed malicious finding, or an uncertain finding that
cannot be cleared. The gate fails safe: when in doubt, BLOCK and explain.
Report confirmed findings (file:line, category, why), uncertain findings needing human
judgement, and a one-line dismissal summary per category so a human can spot-check. Never
silently drop a flag.
What is in scope (and the seams it deliberately covers)
- Whole source tree, including instruction markdown that an LLM executes:
.claude/agents/**, .claude/skills/**, CLAUDE.md, and AGENTS.md are scanned for
prompt injection / exfiltration / permission-escalation directives. Prose docs (docs/**,
README.md) are out of scope - they are not executed. .env is never read.
package.json content check: install lifecycle hooks and newly-added
transaction/web3/miner or non-registry (git/url/tarball) dependencies.
- Path-aware priors:
child_process/exec in scripts/, headless/, and tests/ is
dev tooling and demoted below the gate threshold, so the HIGH band tracks real risk in
shipped src/** and server/**. A --gate run (and npm test) fails only on a surviving
HIGH finding, so a clean tree is green and a planted drainer is not.
Scope and limits (say these in the report, do not pretend otherwise)
- The static line scan cannot see: aliased or multi-line or dynamically-built call forms
(e.g.
const f = fetch; f(url, {body: secret})), an exfil URL assembled from variables or
fetched at runtime, semantically paraphrased instruction injection (the ai-* rules catch
phrasings, not meaning), and anything behind eval/runtime indirection. The agent
compensates by READING context, but neither runs the code in a sandbox - say so.
- Dependencies are checked by content, not by diff or depth.
node_modules is NOT walked
and the lockfile's transitive tree is NOT audited. The manifest check catches a direct risky
or non-registry dep and install hooks, but a malicious TRANSITIVE dependency, or a
compromised version of an allowed one, is invisible here. The realistic token-theft path is
new wallet-transaction code (which the web3/key-exfil rules cover) or a new dependency -
pair this gate with npm audit, a lockfile diff, and a review of any package.json change.
- Read-only. This skill never edits, reverts, or quarantines code. It produces a verdict;
remediation is a human decision.
Relationship to the other reviewers
| Concern | Owner |
|---|
| Deliberately planted malicious code | this skill |
| Accidental security/privacy mistakes (auth, SQLi, leaked secrets) | privacy-security-review |
| Schema / persisted-state safety | migration-safety |
| Three-host / IWorld parity | cross-platform-sync |
| Sim determinism | tests/architecture.test.ts |