From 6548825083718e6acb775bd0647c305b97739a2f Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 2 May 2026 16:58:07 -0700 Subject: [PATCH] fix(scanner): ignore full-line comments for source rules --- src/security/skill-scanner.test.ts | 9 +++++++++ src/security/skill-scanner.ts | 15 ++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/security/skill-scanner.test.ts b/src/security/skill-scanner.test.ts index 93984e7611a..b0e690bc56f 100644 --- a/src/security/skill-scanner.test.ts +++ b/src/security/skill-scanner.test.ts @@ -265,6 +265,15 @@ const match = /^keychain:(.+)$/.exec(value); expect(findings.some((f) => f.ruleId === "dangerous-exec")).toBe(false); }); + it("does not use full-line comments as source-rule context", () => { + const source = ` +const env = process.env; +// fetch() can reach the endpoint later. +`; + const findings = scanSource(source, "plugin.ts"); + expect(findings.some((f) => f.ruleId === "env-harvesting")).toBe(false); + }); + it("returns empty array for clean plugin code", () => { const source = ` export function greet(name: string): string { diff --git a/src/security/skill-scanner.ts b/src/security/skill-scanner.ts index 4a9d22fd908..01bbeefdbf6 100644 --- a/src/security/skill-scanner.ts +++ b/src/security/skill-scanner.ts @@ -233,9 +233,18 @@ function isBenignMemberExecMatch(line: string, match: RegExpExecArray): boolean return !/\b(?:cp|childProcess|child_process)\s*\.\s*exec\s*\(/.test(line); } +function stripFullLineCommentsForHeuristics(source: string): string { + return source + .split("\n") + .map((line) => (line.trimStart().startsWith("//") ? "" : line)) + .join("\n"); +} + export function scanSource(source: string, filePath: string): SkillScanFinding[] { const findings: SkillScanFinding[] = []; const lines = source.split("\n"); + const heuristicSource = stripFullLineCommentsForHeuristics(source); + const heuristicLines = heuristicSource.split("\n"); const matchedLineRules = new Set(); // --- Line rules --- @@ -291,10 +300,10 @@ export function scanSource(source: string, filePath: string): SkillScanFinding[] continue; } - if (!rule.pattern.test(source)) { + if (!rule.pattern.test(heuristicSource)) { continue; } - if (rule.requiresContext && !rule.requiresContext.test(source)) { + if (rule.requiresContext && !rule.requiresContext.test(heuristicSource)) { continue; } @@ -302,7 +311,7 @@ export function scanSource(source: string, filePath: string): SkillScanFinding[] let matchLine = 0; let matchEvidence = ""; for (let i = 0; i < lines.length; i++) { - if (rule.pattern.test(lines[i])) { + if (rule.pattern.test(heuristicLines[i] ?? "")) { matchLine = i + 1; matchEvidence = lines[i].trim(); break;