Skip to content

fix(security): SecurityValidator schema mismatch + fail-closed#1014

Open
christauff wants to merge 1 commit intodanielmiessler:mainfrom
christauff:fix/securityvalidator-schema-failclosed
Open

fix(security): SecurityValidator schema mismatch + fail-closed#1014
christauff wants to merge 1 commit intodanielmiessler:mainfrom
christauff:fix/securityvalidator-schema-failclosed

Conversation

@christauff
Copy link
Copy Markdown
Contributor

Summary

Fixes three security vulnerabilities in SecurityValidator.hook.ts discovered through vulnerability analysis of the leaked Claude Code source (instructkr/claude-code, 13.8k+ stars, accidentally published via npm source maps on 2026-03-31).

1. decision: 'ask' Zod Schema Mismatch (Critical)

The hook outputs {"decision": "ask"} for confirm-level operations (force push, recursive delete, cloud ops, database ops, confirmWrite paths). However, Claude Code's Zod validation schema at types/hooks.ts:64 only accepts z.enum(['approve', 'block']) for the top-level decision field. The value 'ask' fails schema validation, CC treats it as a non-blocking error, and the operation proceeds without user confirmation.

Every confirm-level security control is silently non-functional -- force pushes, recursive deletions, cloud resource destruction, and database operations all pass through without prompting.

Fix: Use the correct CC schema path -- hookSpecificOutput with hookEventName: 'PreToolUse' and permissionDecision: 'ask' -- which IS supported by z.enum(['allow', 'deny', 'ask']) in PermissionRule.ts:26.

2. Fail-Open to Fail-Closed on All Error Paths

Five error paths returned {"continue": true} (fail-open), allowing operations to proceed when the security validator encountered errors:

  • Missing patterns.yaml: now returns hardcoded deny rules
  • YAML parse error: now returns hardcoded deny rules
  • Stdin JSON parse failure: now process.exit(2)
  • Unhandled exception: now process.exit(2)
  • Stdin timeout: now process.exit(2)

CC's hook execution model treats exit code 2 as blocking (operation denied), while all other non-zero exit codes are non-blocking errors (operation allowed). This makes process.exit(2) the correct fail-closed behavior.

3. Updated Doc Header

Reflects the new fail-closed security model.

Discovery Context

These vulnerabilities were identified by analyzing how Claude Code processes hook output -- specifically the Zod schema validation in types/hooks.ts and the exit code handling in utils/hooks.ts:2647-2697. Two prior CC CVEs (CVE-2025-59536 and CVE-2026-21852, both from Check Point Research) established precedent for this class of hook security analysis.

Test Plan

  • Verify safe operations (ls, cat) still return {"continue": true} (allow)
  • Verify blocked operations still exit(2) (block)
  • Verify confirm operations (git push --force) now output valid hookSpecificOutput JSON
  • Verify malformed stdin causes exit(2) (fail-closed) instead of {"continue": true}
  • Verify missing patterns.yaml returns hardcoded deny rules (not empty permissive config)

Generated with Claude Code

…losed

Three security issues found via vulnerability analysis of the leaked Claude Code
source (instructkr/claude-code, 13.8k stars). The CC source revealed how hook
JSON output is validated, exposing a critical schema mismatch that silently
breaks all confirm-level security controls.

## Fixes
### 1. `decision: 'ask'` Zod schema mismatch (CRITICAL)

The hook outputs `{"decision": "ask"}` for confirm-level operations, but CC's
Zod schema (`types/hooks.ts:64`) only accepts `z.enum(['approve', 'block'])`.
The value 'ask' fails validation, CC treats it as a non-blocking error, and the
operation proceeds WITHOUT user confirmation.

**Every confirm-level protection was silently non-functional:**
- git push --force, git reset --hard
- rm -r (recursive deletion)
- All cloud/infra operations (AWS, GCP, Terraform, kubectl)
- All database operations (DROP, DELETE, TRUNCATE)
- All confirmWrite file protections (hooks, SSH config)

**Fix:** Use the correct CC schema path: `hookSpecificOutput` with
`hookEventName: 'PreToolUse'` and `permissionDecision: 'ask'`, which IS
supported by `z.enum(['allow', 'deny', 'ask'])` in `PermissionRule.ts:26`.

### 2. Fail-open → fail-closed on all error paths

Four error paths returned `{"continue": true}` (fail-open), allowing operations
to proceed when the security validator itself encountered errors:
- Missing patterns.yaml → was empty permissive config, now hardcoded deny rules
- YAML parse error → was empty permissive config, now hardcoded deny rules
- stdin JSON parse failure → was `{"continue": true}`, now `process.exit(2)`
- Unhandled exception in main() → was `{"continue": true}`, now `process.exit(2)`
- stdin 200ms timeout → was `{"continue": true}`, now `process.exit(2)`

### 3. Updated doc header to reflect fail-closed security model

## Discovery

These vulnerabilities were identified through static analysis of the Claude Code
source code that was accidentally published via npm source maps on 2026-03-31
(archived at github.com/instructkr/claude-code). Analysis of CC's hook execution
model in `utils/hooks.ts` revealed that exit code 2 = blocking, while all other
non-zero exit codes are treated as non-blocking errors that allow the operation.
This, combined with the Zod schema analysis in `types/hooks.ts`, confirmed the
`decision: 'ask'` mismatch.

Two prior CC CVEs (CVE-2025-59536, CVE-2026-21852) reported by Check Point
Research established precedent for this class of hook security analysis.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
justinkatz94-glitch pushed a commit to justinkatz94-glitch/Personal_AI_Infrastructure that referenced this pull request Apr 3, 2026
…lmiessler#1014)

Three security fixes:

1. decision:'ask' fails CC Zod validation (only accepts 'approve'|'block')
   - Changed to hookSpecificOutput with permissionDecision:'ask'
   - Every confirm-level control was silently non-functional

2. Five error paths fail-open (continue:true) instead of fail-closed
   - Now use process.exit(2) which CC treats as blocking denial

3. Added extractWritePathsFromBash() for deeper command analysis
   - Catches writeFileSync, shell redirections, tee, sed -i, cp/mv

Closes danielmiessler#1014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant