xploitscan 1.1.3 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -43512,7 +43512,25 @@ var ALWAYS_IGNORE = [
43512
43512
  "*.map",
43513
43513
  "package-lock.json",
43514
43514
  "pnpm-lock.yaml",
43515
- "yarn.lock"
43515
+ "yarn.lock",
43516
+ // Intentionally-vulnerable test corpora. Security tools (XploitScan,
43517
+ // Semgrep, Bearer, Gitleaks, Snyk Code) all maintain directories of
43518
+ // known-bad code samples used to verify that rules fire. Scanning
43519
+ // them produces a flood of "critical" findings on the scanner's own
43520
+ // dogfood, drowning the signal from real product code. Skip by
43521
+ // default. Users who genuinely want to scan a fixture directory can
43522
+ // override via .xploitscanignore (the negation syntax `!test-
43523
+ // fixtures/` un-ignores it).
43524
+ //
43525
+ // We only match these as directory names anywhere in the tree, so a
43526
+ // project whose actual source happens to live under a path called
43527
+ // `fixtures-prod/` is unaffected.
43528
+ "test-fixtures",
43529
+ "test-fixtures/**",
43530
+ "__fixtures__",
43531
+ "__fixtures__/**",
43532
+ "vulnerable-samples",
43533
+ "vulnerable-samples/**"
43516
43534
  ];
43517
43535
  async function collectFiles(directory) {
43518
43536
  const ig = ignore.default();
@@ -45362,7 +45380,12 @@ var complianceMap = {
45362
45380
  var consoleLogProduction = {
45363
45381
  id: "VC097",
45364
45382
  title: "Console.log Left in Production Code",
45365
- severity: "low",
45383
+ // Demoted from "low" to "info" 2026-05-11. This is a code-hygiene
45384
+ // signal (leaked debug logs, occasionally PII), not a security
45385
+ // vulnerability in the OWASP sense. Was inflating severity counts
45386
+ // on real codebases (11+ hits on vibecheck's own scan), drowning
45387
+ // the actual security signal.
45388
+ severity: "info",
45366
45389
  category: "Performance",
45367
45390
  description: "console.log statements left in production code can leak sensitive data, slow down rendering, and clutter browser consoles.",
45368
45391
  check(content, filePath) {
@@ -45402,7 +45425,11 @@ var todoLeftInCode = {
45402
45425
  var emptyCatchBlock = {
45403
45426
  id: "VC104",
45404
45427
  title: "Empty Catch Block",
45405
- severity: "medium",
45428
+ // Demoted from "medium" to "info" 2026-05-11. Already a Code-Quality
45429
+ // category — empty catch blocks are a maintainability concern, not a
45430
+ // security vulnerability. Worth flagging, not worth counting as a
45431
+ // security "medium" alongside actual SQL-injection / XSS findings.
45432
+ severity: "info",
45406
45433
  category: "Code Quality",
45407
45434
  description: "Empty catch blocks silently swallow errors, making bugs impossible to diagnose. At minimum, log the error.",
45408
45435
  check(content, filePath) {
@@ -45531,7 +45558,21 @@ For each finding, respond ONLY with a JSON array. No other text.
45531
45558
  Each element: {"index": <number>, "verdict": "real" or "fp", "reason": "<1 sentence>"}`;
45532
45559
  var MAX_FINDINGS_PER_BATCH = 15;
45533
45560
  var MAX_CONTEXT_LINES = 10;
45534
- var MAX_TOTAL_FINDINGS = 50;
45561
+ var DEFAULT_MAX_TOTAL_FINDINGS = 200;
45562
+ var MAX_TOTAL_FINDINGS = (() => {
45563
+ const raw = process.env.XPLOITSCAN_AI_FILTER_MAX;
45564
+ if (!raw) return DEFAULT_MAX_TOTAL_FINDINGS;
45565
+ const n = parseInt(raw, 10);
45566
+ if (!Number.isFinite(n) || n < 1) return DEFAULT_MAX_TOTAL_FINDINGS;
45567
+ return Math.min(n, 1e3);
45568
+ })();
45569
+ var SEVERITY_PRIORITY = {
45570
+ critical: 0,
45571
+ high: 1,
45572
+ medium: 2,
45573
+ low: 3,
45574
+ info: 4
45575
+ };
45535
45576
  function getExpandedContext(content, line, contextLines = MAX_CONTEXT_LINES) {
45536
45577
  const lines = content.split("\n");
45537
45578
  const start = Math.max(0, line - 1 - contextLines);
@@ -45579,8 +45620,13 @@ async function filterFalsePositives(findings, fileContents) {
45579
45620
  const empty = { findings, filteredFindings: [], aiReviewed: false, removedCount: 0, totalBefore: findings.length };
45580
45621
  if (!process.env.ANTHROPIC_API_KEY) return empty;
45581
45622
  if (findings.length === 0) return empty;
45582
- const toReview = findings.slice(0, MAX_TOTAL_FINDINGS);
45583
- const overflow = findings.slice(MAX_TOTAL_FINDINGS);
45623
+ const prioritized = [...findings].sort((a, b) => {
45624
+ const pa = SEVERITY_PRIORITY[(a.severity || "").toLowerCase()] ?? 5;
45625
+ const pb = SEVERITY_PRIORITY[(b.severity || "").toLowerCase()] ?? 5;
45626
+ return pa - pb;
45627
+ });
45628
+ const toReview = prioritized.slice(0, MAX_TOTAL_FINDINGS);
45629
+ const overflow = prioritized.slice(MAX_TOTAL_FINDINGS);
45584
45630
  const totalBefore = findings.length;
45585
45631
  const byFile = /* @__PURE__ */ new Map();
45586
45632
  for (const f of toReview) {
@@ -48182,7 +48228,7 @@ async function cursorInstallCommand(opts = {}) {
48182
48228
  var program = new Command();
48183
48229
  program.name("xploitscan").description(
48184
48230
  "AI security scanner for vibe-coded apps. Find vulnerabilities before attackers do."
48185
- ).version("1.1.3");
48231
+ ).version("1.1.5");
48186
48232
  program.command("scan").description("Scan a directory for security vulnerabilities").argument("[directory]", "Directory to scan", ".").option("--no-ai", "Skip AI-powered analysis").option(
48187
48233
  "-f, --format <format>",
48188
48234
  "Output format: terminal, json, sarif, splunk-hec, elastic-ecs, datadog-logs",