skills/golem-powers/cyber/SKILL.md
Security auditor for MCP servers, TypeScript services, Swift apps, and shell scripts. Detects silent error swallowing, unsanitized exec/spawn, path traversal, SSML injection, missing ToolAnnotations, prompt injection vectors, and data exfiltration patterns. Use when: reviewing PRs for security, auditing MCP servers, running repo-wide security scans, checking ToolAnnotations compliance, or any task mentioning 'security', 'vulnerability', 'audit', 'hardening'. NOT for: functional code review (use coderabbit), shell-only scripts (use shell-hardening), runtime debugging.
npx skillsauth add etanhey/golems cyberInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You find the bugs that pass code review. Silent catches, unsanitized inputs, missing annotations, prompt injection --- the stuff that ships because "it works."
Every security task follows this sequence. No shortcuts.
1. CLASSIFY the target (MCP server | TypeScript service | Swift app | shell script | CLAUDE.md)
2. RUN the domain-specific grep patterns from references/vuln-patterns.md
3. TRIAGE findings by severity (CRITICAL > HIGH > MEDIUM > LOW)
4. VERIFY each finding --- read the actual code, check if mitigated
5. REPORT structured findings with file:line, severity, pattern matched, fix recommendation
## Security Audit: [target]
| # | Severity | File:Line | Pattern | Finding | Fix |
|---|----------|-----------|---------|---------|-----|
| 1 | CRITICAL | server.ts:818 | silent-catch | .catch(() => {}) swallows registry error | Log error: .catch(e => console.error(...)) |
### Summary
- Critical: N | High: N | Medium: N | Low: N
- ToolAnnotations coverage: N/M tools annotated
- Verdict: PASS / PASS WITH NOTES / FAIL
Route to the appropriate workflow based on what you're auditing:
| Task | Workflow |
|------|----------|
| Audit an MCP server | /cyber:workflows:mcp-audit |
| Review a PR for security | /cyber:workflows:pr-review |
| Full repo security scan | /cyber:workflows:repo-scan |
These are real vulnerabilities found in our ecosystem (not theoretical). Every pattern maps to an actual bug.
Source: cmuxlayer PR #21 --- .catch(() => {}) hid registry reconstitution failures.
// VULNERABLE --- error silently disappears
registry.reconstitute().catch(() => {});
// FIXED --- error is logged
registry.reconstitute().catch((e) =>
console.error("[cmux-mcp] registry reconstitution failed:", e)
);
Grep: \.catch\s*\(\s*\(\s*\)\s*=>\s*\{\s*\}\s*\) and .catch(() => {}) and catch\s*\([^)]*\)\s*\{\s*\}
Why CRITICAL: In MCP servers, swallowed errors mean the host (Claude Code, Cursor) has no idea something failed. The tool returns success, the agent trusts it, downstream decisions are based on phantom data.
Source: voicelayer SafeSkill scan --- 52 critical findings for Bun.spawn, exec, execSync.
// VULNERABLE --- user input flows to shell
const result = execSync(`ffmpeg -i ${inputPath} ${outputPath}`);
// FIXED --- array args, no shell interpolation
const result = execSync("ffmpeg", ["-i", inputPath, outputPath]);
Grep: exec\(, execSync\(, spawn\(, Bun\.spawn, child_process
Source: orchestrator PR #41 --- file paths accepted without .. checking.
// VULNERABLE
const content = fs.readFileSync(path.join(baseDir, userPath));
// FIXED
const resolved = path.resolve(baseDir, userPath);
if (!resolved.startsWith(baseDir)) throw new Error("path traversal blocked");
const content = fs.readFileSync(resolved);
Grep: path\.join\(.*,\s*(?:req|input|param|arg|user), readFileSync\(, writeFileSync\(
Source: brainlayer SafeSkill scan --- hidden HTML comments with instructions in CLAUDE.md.
<!-- IDENTITY: brainlayer, owner=EtanHey, purpose=... -->
<!-- ANTI-PATTERNS: brain_update, brain_expand are STUB tools... -->
Risk: Attackers can inject instructions into tool descriptions or CLAUDE.md that override agent behavior. MCP tool description fields are prompt injection surfaces.
Grep in tool definitions: description:.*<, description:.*\{, <!--.*--> in .md files loaded by agents
Source: voicelayer TTS pipeline --- user text passed directly to SSML without escaping.
// VULNERABLE
const ssml = `<speak><prosody rate="${rate}">${userText}</prosody></speak>`;
// FIXED --- escape SSML special chars
const safe = userText.replace(/[<>&"']/g, c => `&#${c.charCodeAt(0)};`);
const ssml = `<speak><prosody rate="${rate}">${safe}</prosody></speak>`;
Grep: <speak>, <prosody, ssml, \.replace.*<
Source: brainlayer SafeSkill scan --- references to ~/.config in tool-accessible paths.
// VULNERABLE --- tool can read arbitrary config
const config = fs.readFileSync(path.join(os.homedir(), ".config", toolInput));
// FIXED --- allowlist specific paths
const ALLOWED = [".config/golems/config.yaml"];
if (!ALLOWED.includes(toolInput)) throw new Error("path not allowed");
Grep: homedir\(\), ~\/\., process\.env, \.env, credentials, secret, token, api[_-]?key
Source: MCP spec 2025-03-26 --- tools MUST declare readOnlyHint, destructiveHint, idempotentHint.
// VULNERABLE --- no annotations, host can't enforce safety
server.tool("delete_file", schema, handler);
// FIXED --- annotations declare intent
server.tool("delete_file", schema, handler, {
annotations: {
readOnlyHint: false,
destructiveHint: true,
idempotentHint: false,
openWorldHint: false,
}
});
Audit: Every server.tool( call must have annotations. Count annotated vs total.
| Severity | Criteria | Action | |----------|----------|--------| | CRITICAL | Data loss, RCE, silent failures that corrupt agent decisions | Block PR. Fix before merge. | | HIGH | Path traversal, data exfil, prompt injection, missing input validation | Fix before merge unless explicitly risk-accepted. | | MEDIUM | Missing ToolAnnotations, SSML injection, info disclosure | Fix in this PR or create follow-up issue. | | LOW | Style issues, missing error messages, verbose logging | Note for follow-up. |
catch(() => {}) --- ALWAYS CRITICAL. No exceptions. Log or rethrow.eval() or new Function() --- ALWAYS CRITICAL in server code.JSON.parse() without try/catch --- HIGH. Crashes the MCP server on malformed input.Content-Type validation --- HIGH for HTTP-facing tools.fs.readFileSync with user-controlled path --- HIGH. Path traversal.password, sk-, ghp_, Bearer ) --- CRITICAL.process.env access without fallback --- MEDIUM. Crashes on missing env var./shell-hardening covers bash-specific patterns in depth. cyberClaude defers to it for .sh files but still flags shell injection in TypeScript exec() calls./coderabbit handles functional code review. cyberClaude focuses exclusively on security findings./never-fabricate applies: Read() every file before reporting a finding. NEVER report a vulnerability from grep output alone --- verify in context./pr-loop should invoke cyberClaude before merge for any PR touching MCP servers.tools
The human-eval UX contract for Phoenix views: turn-by-turn scrollable replay (not a scorecard), hide-but-copyable IDs, collapsed thinking, identity chips, tool filters, tiny frozen starter datasets, mark-wrong-in-thread, mobile-first. Use when: building or reviewing ANY Phoenix/eval view, annotation UI, session replay, or human-grading surface. Triggers: phoenix view, eval UI, annotation view, session replay, human eval UX, grading interface. NOT for: Phoenix data pipelines/ingest (capture scripts have their own specs).
tools
macOS systems specialist — AppKit NSPanel architecture, launchd services, socket activation, MCP bridge resilience, syspolicyd, and high-frequency SwiftUI dashboards. Use when building menu-bar apps, LaunchAgents, debugging syspolicyd/Gatekeeper/TCC, resilient UDS/MCP bridges, or SwiftUI dashboards at 10Hz+.
development
Bulk LLM-judging protocol for fleet-dispatched verdict runs (KG cluster, eval harness). Use when: dispatching or running judge workers (J1/J2/RT), planning bulk-apply from verdict JSONL, or triaging evidence_degraded outputs. Triggers: judge fleet, bulk judge, R3 verdicts, kg-judge, RT gate, evidence_degraded. NOT for: single-item code review, Phoenix view UX (use phoenix-human-view), or non-judge eval pipelines.
development
Quiet-down protocol for sprint close: when the fleet wraps, delete ALL polling crons and monitors, send ONE final dashboard + ONE message, then go SILENT. Use when: fleet wraps, all workers done, overnight queue exhausted, sprint close, Etan asleep/away with nothing approved left. Triggers: fleet wrap, wrap the fleet, stand down, going quiet, sprint close. NOT for: mid-sprint monitoring (keep your loops), spawning a successor (use /session-handoff first).