fix(scanner): ignore benign member exec matches · openclaw/openclaw@4be4c47
vincentkoc
·
2026-05-03
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -164,6 +164,14 @@ exec(cmd);
|
164 | 164 | source: ` |
165 | 165 | const cp = require("child_process"); |
166 | 166 | cp.spawn("node", ["server.js"]); |
| 167 | +`, |
| 168 | +expected: { ruleId: "dangerous-exec", severity: "critical" as const }, |
| 169 | +}, |
| 170 | +{ |
| 171 | +name: "detects child_process namespaced exec usage", |
| 172 | +source: ` |
| 173 | +const cp = require("child_process"); |
| 174 | +cp.exec("node server.js"); |
167 | 175 | `, |
168 | 176 | expected: { ruleId: "dangerous-exec", severity: "critical" as const }, |
169 | 177 | }, |
@@ -247,6 +255,16 @@ const options: ExecOptions = { timeout: 5000 };
|
247 | 255 | expect(findings.some((f) => f.ruleId === "dangerous-exec")).toBe(false); |
248 | 256 | }); |
249 | 257 | |
| 258 | +it("does not flag RegExp.exec when child_process appears elsewhere", () => { |
| 259 | +const source = ` |
| 260 | +import type { ExecOptions } from "child_process"; |
| 261 | +const options: ExecOptions = {}; |
| 262 | +const match = /^keychain:(.+)$/.exec(value); |
| 263 | +`; |
| 264 | +const findings = scanSource(source, "plugin.ts"); |
| 265 | +expect(findings.some((f) => f.ruleId === "dangerous-exec")).toBe(false); |
| 266 | +}); |
| 267 | + |
250 | 268 | it("returns empty array for clean plugin code", () => { |
251 | 269 | const source = ` |
252 | 270 | export function greet(name: string): string { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -219,6 +219,20 @@ function truncateEvidence(evidence: string, maxLen = 120): string {
|
219 | 219 | return `${evidence.slice(0, maxLen)}…`; |
220 | 220 | } |
221 | 221 | |
| 222 | +function isBenignMemberExecMatch(line: string, match: RegExpExecArray): boolean { |
| 223 | +const command = match[1]; |
| 224 | +if (command !== "exec") { |
| 225 | +return false; |
| 226 | +} |
| 227 | + |
| 228 | +const matchIndex = match.index; |
| 229 | +if (matchIndex <= 0 || line[matchIndex - 1] !== ".") { |
| 230 | +return false; |
| 231 | +} |
| 232 | + |
| 233 | +return !/\b(?:cp|childProcess|child_process)\s*\.\s*exec\s*\(/.test(line); |
| 234 | +} |
| 235 | + |
222 | 236 | export function scanSource(source: string, filePath: string): SkillScanFinding[] { |
223 | 237 | const findings: SkillScanFinding[] = []; |
224 | 238 | const lines = source.split("\n"); |
@@ -242,6 +256,10 @@ export function scanSource(source: string, filePath: string): SkillScanFinding[]
|
242 | 256 | continue; |
243 | 257 | } |
244 | 258 | |
| 259 | +if (rule.ruleId === "dangerous-exec" && isBenignMemberExecMatch(line, match)) { |
| 260 | +continue; |
| 261 | +} |
| 262 | + |
245 | 263 | // Special handling for suspicious-network: check port |
246 | 264 | if (rule.ruleId === "suspicious-network") { |
247 | 265 | const port = Number.parseInt(match[1], 10); |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。