@runsec/mcp 1.0.73 → 1.0.75
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/data/trufflehog-config.yaml +1 -1
- package/dist/index.js +54 -7
- package/package.json +1 -1
|
@@ -353,7 +353,7 @@ detectors:
|
|
|
353
353
|
- email
|
|
354
354
|
- e-mail
|
|
355
355
|
regex:
|
|
356
|
-
pattern: '(?i)(?:email|e-mail)\s*[:=]\s*[\x27"]?
|
|
356
|
+
pattern: '(?i)(?:email|e-mail)\s*[:=]\s*[\x27"]?[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}[\x27"]?'
|
|
357
357
|
|
|
358
358
|
- name: PII Phone RU
|
|
359
359
|
keywords:
|
package/dist/index.js
CHANGED
|
@@ -413,7 +413,8 @@ 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
|
|
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;
|
|
417
418
|
var LOCKFILE_BASENAMES = /^(?:poetry\.lock|package-lock\.json|pnpm-lock\.yaml|yarn\.lock|cargo\.lock|composer\.lock|gemfile\.lock)$/i;
|
|
418
419
|
function hasEnvironmentInterpolation(text) {
|
|
419
420
|
return ENV_INTERP_RE.test(text);
|
|
@@ -431,8 +432,37 @@ function isLockfileOrModulesPath(relPath) {
|
|
|
431
432
|
function isTrufflehogVerified(verifiedFlag, description) {
|
|
432
433
|
return verifiedFlag || /\(verified\)/i.test(description);
|
|
433
434
|
}
|
|
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;
|
|
448
|
+
}
|
|
434
449
|
|
|
435
450
|
// 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" };
|
|
463
|
+
}
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
436
466
|
var PRIMARY_LOG_THRESHOLD = 0.8;
|
|
437
467
|
var CONFIDENCE_THRESHOLD = PRIMARY_LOG_THRESHOLD;
|
|
438
468
|
var ELITE_LOW_CONFIDENCE_CAP = 0.28;
|
|
@@ -823,6 +853,10 @@ function attackPathConcrete(finding, confidence, eliteHard, allReasons, snippet)
|
|
|
823
853
|
return confidence >= PRIMARY_LOG_THRESHOLD;
|
|
824
854
|
}
|
|
825
855
|
function baseConfidenceForFinding(finding, phase1, relPath, category, repoRoot) {
|
|
856
|
+
const absolute = resolveAbsoluteSuppression(finding, relPath);
|
|
857
|
+
if (absolute) {
|
|
858
|
+
return [absolute.cap, [absolute.reason]];
|
|
859
|
+
}
|
|
826
860
|
const reasons = [];
|
|
827
861
|
let score = category === "secrets" ? 0.9 : category === "dependencies" ? 0.78 : 0.82;
|
|
828
862
|
const title = finding.description;
|
|
@@ -842,8 +876,8 @@ function baseConfidenceForFinding(finding, phase1, relPath, category, repoRoot)
|
|
|
842
876
|
if (isUnverifiedTrufflehogSecret(finding)) {
|
|
843
877
|
const secretBlob = `${finding.match_text} ${finding.snippet ?? ""}`;
|
|
844
878
|
if (hasEnvironmentInterpolation(secretBlob)) {
|
|
845
|
-
score = Math.min(score,
|
|
846
|
-
reasons.push("
|
|
879
|
+
score = Math.min(score, ABSOLUTE_ENV_INTERP_CAP);
|
|
880
|
+
reasons.push("environment_variable_interpolation");
|
|
847
881
|
}
|
|
848
882
|
if (isLockfileOrModulesPath(relPath)) {
|
|
849
883
|
score = Math.min(score, 0.1);
|
|
@@ -923,6 +957,7 @@ function downgradeSeverity(severity, cap) {
|
|
|
923
957
|
function enrichAuditFinding(repoRoot, finding, opts) {
|
|
924
958
|
const applyFp = opts?.applyFalsePositiveFilter ?? !isCalibrationTestbedPath(finding.file_path);
|
|
925
959
|
const relPath = finding.file_path.replace(/\\/g, "/");
|
|
960
|
+
const absoluteSuppress = resolveAbsoluteSuppression(finding, relPath);
|
|
926
961
|
const phase1 = phase1ContextResearch(repoRoot, relPath);
|
|
927
962
|
let [conf, reasons] = baseConfidenceForFinding(finding, phase1, relPath, finding.category, repoRoot);
|
|
928
963
|
const [boost, boostReason] = comparativeAnalysisBoost(repoRoot, relPath, applyFp);
|
|
@@ -947,11 +982,18 @@ function enrichAuditFinding(repoRoot, finding, opts) {
|
|
|
947
982
|
}
|
|
948
983
|
}
|
|
949
984
|
}
|
|
950
|
-
|
|
985
|
+
if (absoluteSuppress) {
|
|
986
|
+
conf = Math.min(conf, absoluteSuppress.cap);
|
|
987
|
+
if (!reasons.includes(absoluteSuppress.reason)) {
|
|
988
|
+
reasons.push(absoluteSuppress.reason);
|
|
989
|
+
}
|
|
990
|
+
} else {
|
|
991
|
+
conf = Math.max(0.05, Math.min(1, conf));
|
|
992
|
+
}
|
|
951
993
|
const snippetL = snippetLower(finding);
|
|
952
994
|
const attackConcrete = attackPathConcrete(finding, conf, eliteHard, reasons, snippetL);
|
|
953
995
|
const critique = selfCritique(finding, conf, phase1);
|
|
954
|
-
const primaryOk = conf >= PRIMARY_LOG_THRESHOLD && !hardExcludeFromPrimaryLog(relPath, finding.description, conf, eliteHard);
|
|
996
|
+
const primaryOk = !absoluteSuppress && conf >= PRIMARY_LOG_THRESHOLD && !hardExcludeFromPrimaryLog(relPath, finding.description, conf, eliteHard);
|
|
955
997
|
let severity = finding.severity;
|
|
956
998
|
const originalSeverity = finding.original_severity ?? finding.severity;
|
|
957
999
|
if (reasons.includes("phase1_protection_lib_present") && conf <= 0.25) {
|
|
@@ -959,6 +1001,7 @@ function enrichAuditFinding(repoRoot, finding, opts) {
|
|
|
959
1001
|
} else if (!primaryOk && conf < PRIMARY_LOG_THRESHOLD) {
|
|
960
1002
|
severity = downgradeSeverity(severity, critique.suggested_severity_cap);
|
|
961
1003
|
}
|
|
1004
|
+
const forceSuppressed = Boolean(absoluteSuppress);
|
|
962
1005
|
return {
|
|
963
1006
|
...finding,
|
|
964
1007
|
severity,
|
|
@@ -966,6 +1009,10 @@ function enrichAuditFinding(repoRoot, finding, opts) {
|
|
|
966
1009
|
confidence_score: Math.round(conf * 1e3) / 1e3,
|
|
967
1010
|
confidence_reasons: reasons,
|
|
968
1011
|
primary_log_eligible: primaryOk,
|
|
1012
|
+
...forceSuppressed ? {
|
|
1013
|
+
suppressed: true,
|
|
1014
|
+
suppression_reason: absoluteSuppress.reason
|
|
1015
|
+
} : {},
|
|
969
1016
|
attack_path_concrete: attackConcrete,
|
|
970
1017
|
cognitive: {
|
|
971
1018
|
phase1_context_research: phase1,
|
|
@@ -1063,8 +1110,8 @@ function buildVerdict(primaryFindings) {
|
|
|
1063
1110
|
function applyCognitivePipeline(workspaceRoot, findings) {
|
|
1064
1111
|
const enriched = findings.map((f) => enrichAuditFinding(workspaceRoot, f));
|
|
1065
1112
|
const { kept, duplicates } = deduplicateSameLineFindings(enriched);
|
|
1066
|
-
const primary = kept.filter((f) => f.primary_log_eligible);
|
|
1067
|
-
const suppressed = kept.filter((f) => !f.primary_log_eligible).concat(duplicates);
|
|
1113
|
+
const primary = kept.filter((f) => f.primary_log_eligible && !f.suppressed);
|
|
1114
|
+
const suppressed = kept.filter((f) => !f.primary_log_eligible || f.suppressed).concat(duplicates);
|
|
1068
1115
|
return {
|
|
1069
1116
|
primary,
|
|
1070
1117
|
suppressed,
|