mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 13:43:26 +08:00
fix(hooks): scrub secrets and harden hook security (#348)
* fix(hooks): scrub secrets and harden hook security - Scrub common secret patterns (api_key, token, password, etc.) from observation logs before persisting to JSONL (observe.sh) - Auto-purge observation files older than 30 days (observe.sh) - Strip embedded credentials from git remote URLs before saving to projects.json (detect-project.sh) - Add command prefix allowlist to runCommand — only git, node, npx, which, where are permitted (utils.js) - Sanitize CLAUDE_SESSION_ID in temp file paths to prevent path traversal (suggest-compact.js) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(hooks): address review feedback from CodeRabbit and Cubic - Reject shell command-chaining operators (;|&`) in runCommand, strip quoted sections before checking to avoid false positives (utils.js) - Remove command string from blocked error message to avoid leaking secrets (utils.js) - Fix Python regex quoting: switch outer shell string from double to single quotes so regex compiles correctly (observe.sh) - Add optional auth scheme match (Bearer, Basic) to secret scrubber regex (observe.sh) - Scope auto-purge to current project dir and match only archived files (observations-*.jsonl), not live queue (observe.sh) - Add second fallback after session ID sanitization to prevent empty string (suggest-compact.js) - Preserve backward compatibility when credential stripping changes project hash — detect and migrate legacy directories (detect-project.sh) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(hooks): block $() substitution, fix Bearer redaction, add security tests - Add $ and \n to blocked shell metacharacters in runCommand to prevent command substitution via $(cmd) and newline injection (utils.js) - Make auth scheme group capturing so Bearer/Basic is preserved in redacted output instead of being silently dropped (observe.sh) - Add 10 unit tests covering runCommand allowlist blocking (rm, curl, bash prefixes) and metacharacter rejection (;|&`$ chaining), plus error message leak prevention (utils.test.js) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(hooks): scrub parse-error fallback, strengthen security tests Address remaining reviewer feedback from CodeRabbit and Cubic: - Scrub secrets in observe.sh parse-error fallback path (was writing raw unsanitized input to observations file) - Remove redundant re.IGNORECASE flag ((?i) inline flag already set) - Add inline comment documenting quote-stripping limitation trade-off - Fix misleading test name for error-output test - Add 5 new security tests: single-quote passthrough, mixed quoted+unquoted metacharacters, prefix boundary (no trailing space), npx acceptance, and newline injection - Improve existing quoted-metacharacter test to actually exercise quote-stripping logic Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(security): block $() and backtick inside quotes in runCommand Shell evaluates $() and backticks inside double quotes, so checking only the unquoted portion was insufficient. Now $ and ` are rejected anywhere in the command string, while ; | & remain quote-aware. Addresses CodeRabbit and Cubic review feedback on PR #348. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -339,6 +339,20 @@ function commandExists(cmd) {
|
||||
* @param {object} options - execSync options
|
||||
*/
|
||||
function runCommand(cmd, options = {}) {
|
||||
// Allowlist: only permit known-safe command prefixes
|
||||
const allowedPrefixes = ['git ', 'node ', 'npx ', 'which ', 'where '];
|
||||
if (!allowedPrefixes.some(prefix => cmd.startsWith(prefix))) {
|
||||
return { success: false, output: 'runCommand blocked: unrecognized command prefix' };
|
||||
}
|
||||
|
||||
// Reject shell metacharacters. $() and backticks are evaluated inside
|
||||
// double quotes, so block $ and ` anywhere in cmd. Other operators
|
||||
// (;|&) are literal inside quotes, so only check unquoted portions.
|
||||
const unquoted = cmd.replace(/"[^"]*"/g, '').replace(/'[^']*'/g, '');
|
||||
if (/[;|&\n]/.test(unquoted) || /[`$]/.test(cmd)) {
|
||||
return { success: false, output: 'runCommand blocked: shell metacharacters not allowed' };
|
||||
}
|
||||
|
||||
try {
|
||||
const result = execSync(cmd, {
|
||||
encoding: 'utf8',
|
||||
|
||||
Reference in New Issue
Block a user