fix(llm-security): normalization/discovery evasion + SIG embedded-base64 & custom rules (#21,#23,#30,#36,#42,#52,#55)
#21 the bash normalizer decoded only \xHH, leaving ANSI-C octal/\u/\U forms literal so canonical rm/curl never surfaced; now decodes all three. #23 file-discovery keyed on extname so .env.local/.env.example (extname .local/.example) were silently skipped; now matches multi-part suffixes. #42 a legitimate leading UTF-8 BOM was flagged HIGH (and the tool's own auto-cleaner refused to strip it); pos-0 BOM now excepted. #52 collapseLetterSpacing used a literal space, letting multi-space/tab spacing evade; now [ \t]+. #55 redact(_,60,0) did slice(-0) and leaked the whole unredacted URL; showEnd===0 now means no tail. #30 embedded base64 (const x = "<base64>") never satisfied the whole-string decode, so the SIG identity engine never saw it; added decodeEmbeddedBase64 as an OPT-IN param on normalizeForScan (default off — appending a decoded copy would double-count per-match findings, e.g. content-extractor's injection scan) and enabled it only in signature-scanner, which dedups variants. #36 signature-scanner ignored the documented sig.custom_rules_path policy option; now loads+merges custom rules through the same family filter. 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
b224e18b42
commit
21c6c2b534
11 changed files with 602 additions and 42 deletions
|
|
@ -81,7 +81,21 @@ export async function discoverFiles(targetPath, opts = {}) {
|
|||
} else if (entry.isFile()) {
|
||||
const ext = extname(entry.name).toLowerCase();
|
||||
// Accept known text extensions or extensionless files (Dockerfile, Makefile, etc.)
|
||||
const isKnownText = TEXT_EXTENSIONS.has(ext);
|
||||
let isKnownText = TEXT_EXTENSIONS.has(ext);
|
||||
if (!isKnownText) {
|
||||
// Multi-part extensions (#23, v7.8.3): extname('.env.local') is
|
||||
// '.local', so the multi-part entries in TEXT_EXTENSIONS never
|
||||
// matched and these common secret files were silently skipped.
|
||||
// Check every dot-suffix of the name ('.env.local' for both
|
||||
// '.env.local' and 'backend.env.local').
|
||||
const lowerName = entry.name.toLowerCase();
|
||||
for (let dot = lowerName.indexOf('.'); dot !== -1; dot = lowerName.indexOf('.', dot + 1)) {
|
||||
if (TEXT_EXTENSIONS.has(lowerName.slice(dot))) {
|
||||
isKnownText = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const isExtensionless = ext === '' && !entry.name.startsWith('.');
|
||||
|
||||
if (!isKnownText && !isExtensionless) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue