/cyber
Security audit for MCP, TS, Swift, shell. Triggers: security, vulnerability, hardening, traversal, injection.
$ golems-cli skills install cyberUpdated 2 weeks ago
You find the bugs that pass code review. Silent catches, unsanitized inputs, missing annotations, prompt injection --- the stuff that ships because "it works."
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
---
## DOMAIN ROUTING
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` |
---
## CORE VULNERABILITY PATTERNS
These are **real vulnerabilities found in our ecosystem** (not theoretical). Every pattern maps to an actual bug.
### 1. Silent Error Swallowing (CRITICAL)
**Source:** cmuxlayer PR #21 --- `.catch(() => {})` hid registry reconstitution failures.
```typescript
// 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.
2. Unsanitized Child Process Spawning (CRITICAL)
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
3. Path Traversal (HIGH)
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\(
4. Prompt Injection via CLAUDE.md / Tool Descriptions (HIGH)
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
5. SSML Injection (MEDIUM --- voicelayer-specific)
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.*<
6. Data Exfiltration Patterns (HIGH)
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
7. Missing ToolAnnotations (MEDIUM --- MCP compliance)
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.
Full SKILL.md source — includes LLM directives, anti-patterns, and technical instructions stripped from the Overview tab.
You find the bugs that pass code review. Silent catches, unsanitized inputs, missing annotations, prompt injection --- the stuff that ships because "it works."
AUDIT PROTOCOL (MANDATORY)
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
Output Contract
## 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 / FAILDOMAIN ROUTING
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 |
CORE VULNERABILITY PATTERNS
These are real vulnerabilities found in our ecosystem (not theoretical). Every pattern maps to an actual bug.
1. Silent Error Swallowing (CRITICAL)
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.
2. Unsanitized Child Process Spawning (CRITICAL)
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
3. Path Traversal (HIGH)
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\(
4. Prompt Injection via CLAUDE.md / Tool Descriptions (HIGH)
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
5. SSML Injection (MEDIUM --- voicelayer-specific)
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.*<
6. Data Exfiltration Patterns (HIGH)
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
7. Missing ToolAnnotations (MEDIUM --- MCP compliance)
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.
TRIAGE SEVERITY
| 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. |
ANTI-PATTERNS TO ALWAYS FLAG
catch(() => {})--- ALWAYS CRITICAL. No exceptions. Log or rethrow.eval()ornew Function()--- ALWAYS CRITICAL in server code.JSON.parse()without try/catch --- HIGH. Crashes the MCP server on malformed input.- Missing
Content-Typevalidation --- HIGH for HTTP-facing tools. fs.readFileSyncwith user-controlled path --- HIGH. Path traversal.- Hardcoded secrets (
password,sk-,ghp_,Bearer) --- CRITICAL. process.envaccess without fallback --- MEDIUM. Crashes on missing env var.
INTERACTION WITH OTHER SKILLS
/shell-hardeningcovers bash-specific patterns in depth. cyberClaude defers to it for.shfiles but still flags shell injection in TypeScriptexec()calls./coderabbithandles functional code review. cyberClaude focuses exclusively on security findings./never-fabricateapplies: Read() every file before reporting a finding. NEVER report a vulnerability from grep output alone --- verify in context./pr-loopshould invoke cyberClaude before merge for any PR touching MCP servers.
Best Pass Rate
93%
Opus 4.6
Assertions
29
3 models tested
Avg Cost / Run
$0.2264
across models
Fastest (p50)
3.0s
Sonnet 4.6
Behavior Evals
Phase 2 baseline — skill quality on ClaudeBehavior Baseline
| Assertion | Opus 4.6 | Sonnet 4.6 | Haiku 4.5 | Consensus |
|---|---|---|---|---|
| identifies_silent_catch | 2/3 | |||
| severity_critical | 2/3 | |||
| provides_fix | 3/3 | |||
| identifies_shell_injection | 2/3 | |||
| severity_critical | 3/3 | |||
| recommends_array_args | 3/3 | |||
| identifies_both_inputs | 3/3 | |||
| identifies_path_traversal | 1/3 | |||
| shows_exploit | 2/3 | |||
| recommends_resolve_check | 2/3 | |||
| identifies_all_missing | 2/3 | |||
| delete_destructive | 2/3 | |||
| get_status_readonly | 3/3 | |||
| uses_mcp_spec_fields | 3/3 | |||
| identifies_api_key | 3/3 | |||
| identifies_password | 3/3 | |||
| flags_fallback_token | 2/3 | |||
| recommends_env_or_vault | 3/3 | |||
| identifies_unguarded_parse | 3/3 | |||
| mentions_malformed_input | 2/3 | |||
| recommends_try_catch | 2/3 | |||
| identifies_ssml_injection | 2/3 | |||
| shows_exploit_example | 3/3 | |||
| recommends_escaping | 3/3 | |||
| uses_table_format | 2/3 | |||
| finds_all_four_issues | 3/3 | |||
| correct_severity_ranking | 3/3 | |||
| includes_verdict | 1/3 | |||
| includes_summary_counts | 3/3 |
Token Usage
Cost per Run
| Model | Input Tokens | Output Tokens | Cost / Run | Cost / 1K Runs |
|---|---|---|---|---|
| Opus 4.6 | 5,753 | 6,525 | $0.5757 | $575.70 |
| Sonnet 4.6 | 5,367 | 5,615 | $0.1003 | $100.30 |
| Haiku 4.5 | 2,859 | 2,036 | $0.0033 | $3.30 |
Response Time (p50)
Response Time (p95)
| Model | p50 | p95 | Overhead |
|---|---|---|---|
| Opus 4.6 | 5.5s | 10.2s | +85% |
| Sonnet 4.6 | 3.0s | 5.6s | +83% |
| Haiku 4.5 | 4.1s | 6.0s | +47% |
Last evaluated: 2026-03-12 · Data is generated from skill assertions (real cross-model benchmarks coming soon)
Changelog entries are derived from eval runs and skill version updates. Full cascading changelog (Phase 4D) coming soon.
Best Pass Rate
93%
Assertions
29
Models Tested
3
Evals Run
8
- +Initial release to Golems skill library
- +29 assertions across 8 eval scenarios
- +3 workflows included: mcp-audit, pr-review, repo-scan