fix(llm-security): hook coverage — pathguard on Edit, trifecta window, pipe-to-shell, provider keys (#9,#10,#12,#13,#11-doc)
#9 pathguard registered matcher Write only, so an Edit/MultiEdit to an existing protected file (settings.json, .env, .ssh, the hooks themselves) bypassed it entirely; matcher now Edit|Write (the script already reads only tool_input.file_path). #10 the primary trifecta detector's 20-entry window counted marker lines, so accumulated markers scrolled a real leg out (false negative); the window now counts tool-call entries. #13 pre-edit-secrets caught bare provider keys only inside a quoted label assignment; added anchored patterns for Anthropic sk-ant, OpenAI sk-proj, fine-grained github_pat_, Google AIza, and JWT eyJ (minimum-length guarded against prose false positives). #12 the remote-pipe-to-shell block required a shell immediately after the first pipe, so xargs/sudo/tee/env interposition evaded it and the comment falsely claimed xargs was caught; broadened to reach a shell through intermediate segments while leaving shell-OR fallbacks unblocked. #11 (doc only): knowledge/owasp-skills-top10.md claimed pre-bash-destructive blocks persistence commands — it does not; corrected to mark persistence detection as unimplemented/future (the detector itself is deferred to v8). Suite 2004/0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TcQyMTQfyrsAapaCMPxTtQ
This commit is contained in:
parent
21c6c2b534
commit
8a59d616fb
9 changed files with 337 additions and 6 deletions
|
|
@ -27,12 +27,24 @@ const SECRET_PATTERNS = [
|
|||
{ name: 'Azure AI Services Key', pattern: /Ocp-Apim-Subscription-Key\s*[=:]\s*['"]?[0-9a-f]{32}['"]?/i },
|
||||
{ name: 'GitHub Token', pattern: /(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,}/ },
|
||||
{ name: 'npm Token', pattern: /npm_[A-Za-z0-9]{36}/ },
|
||||
// v7.8.3 #13 — bare provider keys (see knowledge/secrets-patterns.md).
|
||||
// Previously these were caught only when wrapped in a quoted label
|
||||
// assignment (password|secret|token|api_key = "..."); the bare key forms
|
||||
// slipped through.
|
||||
{ name: 'Anthropic API Key', pattern: /\bsk-ant-api03-[A-Za-z0-9_-]{93}\b/ },
|
||||
{ name: 'OpenAI Project Key', pattern: /\bsk-proj-[A-Za-z0-9_-]{40,}\b/ },
|
||||
{ name: 'GitHub Fine-Grained PAT', pattern: /\bgithub_pat_[A-Za-z0-9_]{82}\b/ },
|
||||
{ name: 'Google API Key', pattern: /\bAIza[0-9A-Za-z_-]{35}\b/ },
|
||||
{ name: 'Private Key PEM Block', pattern: /-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/ },
|
||||
{ name: 'JWT Secret', pattern: /JWT[_-]?SECRET\s*[=:]\s*['"][^'"]{8,}['"]/i },
|
||||
{ name: 'Slack/Discord Webhook URL', pattern: /https:\/\/(?:hooks\.slack\.com\/services|discord(?:app)?\.com\/api\/webhooks)\// },
|
||||
{ name: 'Generic credential assignment', pattern: /(?:password|passwd|secret|token|api[_-]?key)\s*[=:]\s*['"][^'"]{8,}['"]/i },
|
||||
{ name: 'Authorization header with token', pattern: /[Bb]earer [A-Za-z0-9\-._~+/]{20,}/ },
|
||||
{ name: 'Database connection string', pattern: /(?:postgres|mysql|mongodb|redis):\/\/[^\s]+@[^\s]+/i },
|
||||
// v7.8.3 #13 — three-part JWT (header.payload.signature, base64url). The
|
||||
// 10-char part minimum keeps prose fragments (eyJabc.def.ghi) from tripping.
|
||||
// Kept last so a Bearer-header context reports as 'Authorization header'.
|
||||
{ name: 'JWT (three-part token)', pattern: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/ },
|
||||
// Policy-defined additional patterns
|
||||
...getPolicyValue('secrets', 'additional_patterns', []).map((p, i) => ({
|
||||
name: `Custom pattern ${i + 1}`,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue