fix(llm-security): misc scanner correctness — reflog FP, diff exact-pass, hex dedupe, SARIF version (#20,#22,#50,#54,#56)

#20 git-forensics' reflog force-push detector had a redundant bare 'reset' term subsuming 'reset:', so any commit subject containing 'reset' tripped it; removed. #22 diff-engine's per-current moved-fallback greedily consumed a baseline candidate a later byte-exact match needed (mislabeling unchanged as new/moved on duplicate fingerprints); a global exact pass now runs before the moved-fallback. #54 memory-poisoning double-reported a 64+ char hex token as both base64 and hex; the base64 check now skips pure-hex tokens.

#56 SARIF output hardcoded driver.version 6.0.0 because the orchestrator called toSARIF() without a version; it now passes the real plugin version from package.json. #50 the VS Code known-malicious blocklist was empty with no explanation (unlike the JetBrains file's 'empty by design' note); added a matching blocklist_note. 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:
Kjell Tore Guttormsen 2026-07-18 10:36:51 +02:00
commit 66e8ce2740
10 changed files with 340 additions and 9 deletions

View file

@ -175,7 +175,13 @@ export function diffFindings(baselineFindings, currentFindings) {
moved: [],
};
// Pass 1: Match current findings against baseline
// Pass 1a: Global EXACT-match pass (same file, line within threshold).
// v7.8.3 (#22): the moved-fallback used to run per-current inside this loop,
// so an earlier unmatched current finding greedily consumed a baseline
// candidate that a LATER current finding needed for a byte-exact match
// (duplicate fingerprints), mislabeling unchanged findings as new/moved.
// Exact matches are now claimed globally before any moved-fallback runs.
const unmatchedCurrent = [];
for (const current of currentFindings) {
const candidates = baselineByFp.get(current.fingerprint);
if (!candidates) {
@ -183,7 +189,6 @@ export function diffFindings(baselineFindings, currentFindings) {
continue;
}
// Try exact match first (same file, line within threshold)
let matched = false;
for (const baseline of candidates) {
if (baseline.matched) continue;
@ -197,9 +202,13 @@ export function diffFindings(baselineFindings, currentFindings) {
break;
}
}
if (matched) continue;
if (!matched) unmatchedCurrent.push(current);
}
// Try moved match (fingerprint matches, location differs)
// Pass 1b: Moved-fallback on the remainder (fingerprint matches, location differs)
for (const current of unmatchedCurrent) {
const candidates = baselineByFp.get(current.fingerprint);
let matched = false;
for (const baseline of candidates) {
if (baseline.matched) continue;
baseline.matched = true;
@ -211,10 +220,9 @@ export function diffFindings(baselineFindings, currentFindings) {
matched = true;
break;
}
if (matched) continue;
// All candidates consumed — this is new
results.new.push(current);
if (!matched) results.new.push(current);
}
// Pass 2: Unmatched baseline findings are resolved