@runsec/mcp 1.0.75 → 1.0.76

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.
Files changed (2) hide show
  1. package/dist/index.js +82 -47
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -413,8 +413,7 @@ var import_node_fs3 = __toESM(require("fs"));
413
413
  var import_node_path3 = __toESM(require("path"));
414
414
 
415
415
  // src/engine/secretHeuristics.ts
416
- var STRICT_ENV_INTERP_RE = /(?:\$\{[A-Z0-9_]+\}|\$[A-Z][A-Z0-9_]{2,}|%\([A-Za-z0-9_.]+\)s|process\.env\.|os\.getenv\(|getenv\(|environ\[)/i;
417
- var ENV_INTERP_RE = STRICT_ENV_INTERP_RE;
416
+ var ENV_INTERP_RE = /(?:\$\{[A-Z0-9_]+\}|\$[A-Z][A-Z0-9_]{2,}|%\([A-Za-z0-9_.]+\)s|process\.env\.|os\.getenv\(|getenv\()/i;
418
417
  var LOCKFILE_BASENAMES = /^(?:poetry\.lock|package-lock\.json|pnpm-lock\.yaml|yarn\.lock|cargo\.lock|composer\.lock|gemfile\.lock)$/i;
419
418
  function hasEnvironmentInterpolation(text) {
420
419
  return ENV_INTERP_RE.test(text);
@@ -432,37 +431,54 @@ function isLockfileOrModulesPath(relPath) {
432
431
  function isTrufflehogVerified(verifiedFlag, description) {
433
432
  return verifiedFlag || /\(verified\)/i.test(description);
434
433
  }
435
- function isStaticLayoutDumpPath(relPath) {
436
- const normalized = relPath.replace(/\\/g, "/").toLowerCase();
437
- const base = normalized.split("/").pop() ?? normalized;
438
- if (base.endsWith(".storyboard") || base.endsWith(".xib") || base.endsWith(".docx")) return true;
439
- if (base.endsWith(".lock") || /\.lock$/i.test(base)) return true;
440
- return false;
441
- }
442
- function matchTextHasStrictEnvInterpolation(matchText, snippet) {
443
- const m = (matchText ?? "").trim();
444
- const s = (snippet ?? "").trim();
445
- if (m && STRICT_ENV_INTERP_RE.test(m)) return true;
446
- if (s && STRICT_ENV_INTERP_RE.test(s)) return true;
447
- return false;
434
+ var LOCKFILE_LAYOUT_RE = /(?:poetry\.lock|package-lock\.json|pnpm-lock\.yaml|yarn\.lock|\.xib|\.storyboard|\.docx)/i;
435
+ function isLockfileLayoutArtifactPath(relPath) {
436
+ return LOCKFILE_LAYOUT_RE.test(relPath.replace(/\\/g, "/"));
448
437
  }
449
438
 
450
439
  // src/engine/cognitiveEngine.ts
451
- var ABSOLUTE_ENV_INTERP_CAP = 0.05;
452
- var ABSOLUTE_STATIC_DUMP_CAP = 0.01;
453
- function resolveAbsoluteSuppression(finding, relPath) {
454
- if (matchTextHasStrictEnvInterpolation(finding.match_text ?? "", finding.snippet ?? "")) {
455
- return { cap: ABSOLUTE_ENV_INTERP_CAP, reason: "environment_variable_interpolation" };
456
- }
457
- const verified = isTrufflehogVerified(
458
- /\(verified\)/i.test(finding.description) || /\(verified\)/i.test(finding.match_text ?? ""),
459
- finding.description
460
- );
461
- if (!verified && isStaticLayoutDumpPath(relPath)) {
462
- return { cap: ABSOLUTE_STATIC_DUMP_CAP, reason: "static_layout_or_lockfile_unverified" };
440
+ var NUCLEAR_HARD_DROP_CONFIDENCE = 0.01;
441
+ var CUSTOMREGEX_UNVERIFIED_CAP = 0.1;
442
+ function findingIsVerified(finding) {
443
+ if (finding.verified === true) return true;
444
+ return isTrufflehogVerified(false, finding.description) || /\(verified\)/i.test(finding.match_text ?? "");
445
+ }
446
+ function applyNuclearHardDrop(finding, relPath) {
447
+ const matchText = finding.match_text ?? "";
448
+ const snippet = finding.snippet ?? "";
449
+ if (ENV_INTERP_RE.test(matchText) || ENV_INTERP_RE.test(snippet)) {
450
+ return { cap: NUCLEAR_HARD_DROP_CONFIDENCE, reason: "env_variable_interpolation" };
451
+ }
452
+ if (!findingIsVerified(finding) && LOCKFILE_LAYOUT_RE.test(relPath)) {
453
+ return { cap: NUCLEAR_HARD_DROP_CONFIDENCE, reason: "lockfile_or_layout_artifact" };
463
454
  }
464
455
  return null;
465
456
  }
457
+ function isCustomRegexFinding(finding) {
458
+ const detector = String(finding.detector_name ?? "").trim().toLowerCase();
459
+ if (detector === "customregex") return true;
460
+ const title = String(finding.title ?? finding.description ?? "");
461
+ if (/customregex/i.test(title)) return true;
462
+ return /(?:^|\.)customregex$/i.test(finding.rule_id) || finding.rule_id.includes("trufflehog.customregex");
463
+ }
464
+ function looksLikeHighEntropyRawToken(finding) {
465
+ const blob = `${finding.match_text ?? ""} ${finding.snippet ?? ""}`.trim();
466
+ if (blob.length < 24 || ENV_INTERP_RE.test(blob)) return false;
467
+ if (/^(?:ghp_|gho_|github_pat_|glpat-|sk-[a-zA-Z0-9]{10,}|AKIA[0-9A-Z]{16}|xox[baprs]-|eyJ[A-Za-z0-9_-]{10,}\.)/i.test(
468
+ blob
469
+ )) {
470
+ return true;
471
+ }
472
+ const compact = blob.replace(/\s+/g, "");
473
+ if (compact.length >= 40 && /^[A-Za-z0-9+/=_-]+$/.test(compact)) return true;
474
+ return false;
475
+ }
476
+ function customRegexNeedsBaseClamp(finding) {
477
+ if (!isCustomRegexFinding(finding)) return false;
478
+ if (findingIsVerified(finding)) return false;
479
+ if (looksLikeHighEntropyRawToken(finding)) return false;
480
+ return true;
481
+ }
466
482
  var PRIMARY_LOG_THRESHOLD = 0.8;
467
483
  var CONFIDENCE_THRESHOLD = PRIMARY_LOG_THRESHOLD;
468
484
  var ELITE_LOW_CONFIDENCE_CAP = 0.28;
@@ -853,13 +869,13 @@ function attackPathConcrete(finding, confidence, eliteHard, allReasons, snippet)
853
869
  return confidence >= PRIMARY_LOG_THRESHOLD;
854
870
  }
855
871
  function baseConfidenceForFinding(finding, phase1, relPath, category, repoRoot) {
856
- const absolute = resolveAbsoluteSuppression(finding, relPath);
857
- if (absolute) {
858
- return [absolute.cap, [absolute.reason]];
872
+ const nuclear = applyNuclearHardDrop(finding, relPath);
873
+ if (nuclear) {
874
+ return [nuclear.cap, [nuclear.reason]];
859
875
  }
860
876
  const reasons = [];
861
877
  let score = category === "secrets" ? 0.9 : category === "dependencies" ? 0.78 : 0.82;
862
- const title = finding.description;
878
+ const title = finding.title ?? finding.description;
863
879
  const sev = (finding.severity || "").toUpperCase();
864
880
  if (category === "code") {
865
881
  if (sev === "CRITICAL" || sev === "ERROR") score = 0.92;
@@ -867,23 +883,27 @@ function baseConfidenceForFinding(finding, phase1, relPath, category, repoRoot)
867
883
  else score = 0.55;
868
884
  } else if (category === "secrets") {
869
885
  if (sev === "CRITICAL") score = 0.95;
870
- else if (finding.match_text.includes("(verified)")) score = 0.93;
886
+ else if (findingIsVerified(finding) || finding.match_text.includes("(verified)")) score = 0.93;
871
887
  if (/pii\s+email/i.test(title) || finding.rule_id.includes("pii-email")) {
872
- const piiVerified = /\(verified\)/i.test(finding.description);
888
+ const piiVerified = findingIsVerified(finding);
873
889
  score = Math.min(score, piiVerified ? 0.45 : 0.32);
874
890
  reasons.push("pii_email_deprioritized");
875
891
  }
876
892
  if (isUnverifiedTrufflehogSecret(finding)) {
877
893
  const secretBlob = `${finding.match_text} ${finding.snippet ?? ""}`;
878
894
  if (hasEnvironmentInterpolation(secretBlob)) {
879
- score = Math.min(score, ABSOLUTE_ENV_INTERP_CAP);
880
- reasons.push("environment_variable_interpolation");
895
+ score = Math.min(score, NUCLEAR_HARD_DROP_CONFIDENCE);
896
+ reasons.push("env_variable_interpolation");
881
897
  }
882
- if (isLockfileOrModulesPath(relPath)) {
883
- score = Math.min(score, 0.1);
884
- reasons.push("lockfile_or_modules_path");
898
+ if (isLockfileOrModulesPath(relPath) || isLockfileLayoutArtifactPath(relPath)) {
899
+ score = Math.min(score, NUCLEAR_HARD_DROP_CONFIDENCE);
900
+ reasons.push("lockfile_or_layout_artifact");
885
901
  }
886
902
  }
903
+ if (customRegexNeedsBaseClamp(finding)) {
904
+ score = Math.min(score, CUSTOMREGEX_UNVERIFIED_CAP);
905
+ reasons.push("customregex_unverified_clamped");
906
+ }
887
907
  }
888
908
  const libs = phase1.protection_libs_detected ?? [];
889
909
  if (libs.length && protectionMatchesMetric(title, libs)) {
@@ -957,7 +977,19 @@ function downgradeSeverity(severity, cap) {
957
977
  function enrichAuditFinding(repoRoot, finding, opts) {
958
978
  const applyFp = opts?.applyFalsePositiveFilter ?? !isCalibrationTestbedPath(finding.file_path);
959
979
  const relPath = finding.file_path.replace(/\\/g, "/");
960
- const absoluteSuppress = resolveAbsoluteSuppression(finding, relPath);
980
+ const nuclearDrop = applyNuclearHardDrop(finding, relPath);
981
+ if (nuclearDrop) {
982
+ return {
983
+ ...finding,
984
+ severity: downgradeSeverity(finding.severity, "LOW"),
985
+ confidence_score: nuclearDrop.cap,
986
+ confidence_reasons: [nuclearDrop.reason],
987
+ primary_log_eligible: false,
988
+ suppressed: true,
989
+ suppression_reason: nuclearDrop.reason,
990
+ attack_path_concrete: false
991
+ };
992
+ }
961
993
  const phase1 = phase1ContextResearch(repoRoot, relPath);
962
994
  let [conf, reasons] = baseConfidenceForFinding(finding, phase1, relPath, finding.category, repoRoot);
963
995
  const [boost, boostReason] = comparativeAnalysisBoost(repoRoot, relPath, applyFp);
@@ -982,18 +1014,18 @@ function enrichAuditFinding(repoRoot, finding, opts) {
982
1014
  }
983
1015
  }
984
1016
  }
985
- if (absoluteSuppress) {
986
- conf = Math.min(conf, absoluteSuppress.cap);
987
- if (!reasons.includes(absoluteSuppress.reason)) {
988
- reasons.push(absoluteSuppress.reason);
989
- }
1017
+ const postNuclear = applyNuclearHardDrop(finding, relPath);
1018
+ if (postNuclear) {
1019
+ conf = Math.min(conf, postNuclear.cap);
1020
+ if (!reasons.includes(postNuclear.reason)) reasons.push(postNuclear.reason);
990
1021
  } else {
991
1022
  conf = Math.max(0.05, Math.min(1, conf));
992
1023
  }
993
1024
  const snippetL = snippetLower(finding);
994
1025
  const attackConcrete = attackPathConcrete(finding, conf, eliteHard, reasons, snippetL);
995
1026
  const critique = selfCritique(finding, conf, phase1);
996
- const primaryOk = !absoluteSuppress && conf >= PRIMARY_LOG_THRESHOLD && !hardExcludeFromPrimaryLog(relPath, finding.description, conf, eliteHard);
1027
+ const hardDropped = Boolean(postNuclear);
1028
+ const primaryOk = !hardDropped && conf >= PRIMARY_LOG_THRESHOLD && !hardExcludeFromPrimaryLog(relPath, finding.description, conf, eliteHard);
997
1029
  let severity = finding.severity;
998
1030
  const originalSeverity = finding.original_severity ?? finding.severity;
999
1031
  if (reasons.includes("phase1_protection_lib_present") && conf <= 0.25) {
@@ -1001,7 +1033,7 @@ function enrichAuditFinding(repoRoot, finding, opts) {
1001
1033
  } else if (!primaryOk && conf < PRIMARY_LOG_THRESHOLD) {
1002
1034
  severity = downgradeSeverity(severity, critique.suggested_severity_cap);
1003
1035
  }
1004
- const forceSuppressed = Boolean(absoluteSuppress);
1036
+ const forceSuppressed = hardDropped;
1005
1037
  return {
1006
1038
  ...finding,
1007
1039
  severity,
@@ -1011,7 +1043,7 @@ function enrichAuditFinding(repoRoot, finding, opts) {
1011
1043
  primary_log_eligible: primaryOk,
1012
1044
  ...forceSuppressed ? {
1013
1045
  suppressed: true,
1014
- suppression_reason: absoluteSuppress.reason
1046
+ suppression_reason: postNuclear.reason
1015
1047
  } : {},
1016
1048
  attack_path_concrete: attackConcrete,
1017
1049
  cognitive: {
@@ -1755,6 +1787,9 @@ function mapTrufflehogFindings(rows, workspaceRoot) {
1755
1787
  asvsTrace: "V6.4.1",
1756
1788
  severity,
1757
1789
  description,
1790
+ title: description,
1791
+ detector_name: detector,
1792
+ verified,
1758
1793
  file_path: rel,
1759
1794
  line,
1760
1795
  match_text: display.slice(0, 200),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runsec/mcp",
3
- "version": "1.0.75",
3
+ "version": "1.0.76",
4
4
  "main": "dist/index.js",
5
5
  "files": [
6
6
  "dist",