@runsec/mcp 1.0.79 → 1.0.80

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 +92 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -435,6 +435,26 @@ var LOCKFILE_LAYOUT_RE = /(?:poetry\.lock|package-lock\.json|pnpm-lock\.yaml|yar
435
435
  function isLockfileLayoutArtifactPath(relPath) {
436
436
  return LOCKFILE_LAYOUT_RE.test(relPath.replace(/\\/g, "/"));
437
437
  }
438
+ var DEV_GENERIC_CREDENTIAL_RE = /(?:postgres:postgres|root:root|root:password|admin:admin|user:password|test:test|guest:guest|changeme:changeme)/i;
439
+ var DEV_DB_HOST_RE = /@(?:dev_db|dev-db|localhost|127\.0\.0\.1|0\.0\.0\.0|host\.docker\.internal|\.local\b|docker\.internal)(?::|\/|$)/i;
440
+ var DEV_DATABASE_URI_RE = /(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis):\/\/(?:[^:@\s]+:[^@\s]+@)?(?:dev_db|dev-db|localhost|127\.0\.0\.1|host\.docker\.internal)/i;
441
+ function blobHasDevDatabaseSecret(text) {
442
+ const blob = (text ?? "").trim();
443
+ if (!blob) return false;
444
+ if (DEV_GENERIC_CREDENTIAL_RE.test(blob)) return true;
445
+ if (DEV_DB_HOST_RE.test(blob)) return true;
446
+ if (DEV_DATABASE_URI_RE.test(blob)) return true;
447
+ return false;
448
+ }
449
+ function findingHasDevDatabaseSecret(finding) {
450
+ const parts = [
451
+ finding.match_text ?? "",
452
+ finding.snippet ?? "",
453
+ finding.description ?? "",
454
+ finding.title ?? ""
455
+ ];
456
+ return parts.some((p) => blobHasDevDatabaseSecret(p));
457
+ }
438
458
  function findingBlobHasEnvInterpolation(finding) {
439
459
  const parts = [
440
460
  finding.match_text ?? "",
@@ -458,6 +478,9 @@ function applyNuclearHardDrop(finding, relPath) {
458
478
  if (ENV_INTERP_RE.test(matchText) || ENV_INTERP_RE.test(snippet) || findingBlobHasEnvInterpolation(finding)) {
459
479
  return { cap: NUCLEAR_HARD_DROP_CONFIDENCE, reason: "env_variable_interpolation" };
460
480
  }
481
+ if (findingHasDevDatabaseSecret(finding)) {
482
+ return { cap: NUCLEAR_HARD_DROP_CONFIDENCE, reason: "dev_database_placeholder" };
483
+ }
461
484
  if (!findingIsVerified(finding) && (LOCKFILE_LAYOUT_RE.test(relPath) || isLockfileOrModulesPath(relPath) || isLockfileLayoutArtifactPath(relPath))) {
462
485
  return { cap: NUCLEAR_HARD_DROP_CONFIDENCE, reason: "lockfile_or_layout_artifact" };
463
486
  }
@@ -496,7 +519,8 @@ function isCustomRegexFinding(finding) {
496
519
  }
497
520
  function looksLikeHighEntropyRawToken(finding) {
498
521
  const blob = `${finding.match_text ?? ""} ${finding.snippet ?? ""}`.trim();
499
- if (blob.length < 24 || ENV_INTERP_RE.test(blob)) return false;
522
+ if (blob.length < 24 || ENV_INTERP_RE.test(blob) || findingHasDevDatabaseSecret(finding)) return false;
523
+ if (/^(?:postgres(?:ql)?|mysql|mongodb|redis):\/\//i.test(blob)) return false;
500
524
  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(
501
525
  blob
502
526
  )) {
@@ -1821,6 +1845,7 @@ function mapTrufflehogFindings(rows, workspaceRoot) {
1821
1845
  if (isLockfileOrModulesPath(rel)) continue;
1822
1846
  const blob = `${display} ${rawSecret} ${description}`;
1823
1847
  if (hasEnvironmentInterpolation(blob)) continue;
1848
+ if (blobHasDevDatabaseSecret(blob)) continue;
1824
1849
  if (detector.toLowerCase() === "customregex") continue;
1825
1850
  }
1826
1851
  const severity = severityForSecret(detector, verified);
@@ -5947,6 +5972,10 @@ function dockerInternalAlternateUploadUrl(url) {
5947
5972
  }
5948
5973
  }
5949
5974
 
5975
+ // src/telemetryClient.ts
5976
+ var import_node_http = __toESM(require("http"));
5977
+ var import_node_https = __toESM(require("https"));
5978
+
5950
5979
  // src/complianceScores.ts
5951
5980
  var SEVERITY_PENALTY = {
5952
5981
  CRITICAL: 15,
@@ -6055,14 +6084,70 @@ function logHubSyncFailure(message, error, targetUrl) {
6055
6084
  }
6056
6085
  console.error(`[runsec] Hub telemetry upload error (scan saved locally): ${message}`);
6057
6086
  }
6058
- async function postHubUpload(url, apiKey, payload) {
6059
- return await fetch(url, {
6060
- method: "POST",
6061
- headers: hubAuthHeaders(apiKey),
6062
- body: JSON.stringify(payload),
6063
- signal: AbortSignal.timeout(HUB_UPLOAD_TIMEOUT_MS)
6087
+ function postHubUploadNodeHttp(url, apiKey, payload) {
6088
+ return new Promise((resolve, reject) => {
6089
+ const body = JSON.stringify(payload);
6090
+ let parsed;
6091
+ try {
6092
+ parsed = new URL(url);
6093
+ } catch (err) {
6094
+ reject(err);
6095
+ return;
6096
+ }
6097
+ const headers = {
6098
+ ...hubAuthHeaders(apiKey),
6099
+ "Content-Length": String(Buffer.byteLength(body))
6100
+ };
6101
+ const lib = parsed.protocol === "https:" ? import_node_https.default : import_node_http.default;
6102
+ const port = parsed.port !== "" ? Number(parsed.port) : parsed.protocol === "https:" ? 443 : 80;
6103
+ const req = lib.request(
6104
+ {
6105
+ hostname: parsed.hostname,
6106
+ port,
6107
+ path: `${parsed.pathname}${parsed.search}`,
6108
+ method: "POST",
6109
+ headers,
6110
+ timeout: HUB_UPLOAD_TIMEOUT_MS
6111
+ },
6112
+ (res) => {
6113
+ const chunks = [];
6114
+ res.on("data", (chunk) => chunks.push(chunk));
6115
+ res.on("end", () => {
6116
+ const text = Buffer.concat(chunks).toString("utf8");
6117
+ const status = res.statusCode ?? 0;
6118
+ resolve({
6119
+ ok: status >= 200 && status < 300,
6120
+ status,
6121
+ statusText: res.statusMessage ?? "",
6122
+ text: async () => text,
6123
+ json: async () => JSON.parse(text || "{}")
6124
+ });
6125
+ });
6126
+ }
6127
+ );
6128
+ req.on("error", reject);
6129
+ req.on("timeout", () => {
6130
+ req.destroy();
6131
+ reject(Object.assign(new Error("Hub upload request timeout"), { code: "ETIMEDOUT" }));
6132
+ });
6133
+ req.write(body);
6134
+ req.end();
6064
6135
  });
6065
6136
  }
6137
+ async function postHubUpload(url, apiKey, payload) {
6138
+ try {
6139
+ return await fetch(url, {
6140
+ method: "POST",
6141
+ headers: hubAuthHeaders(apiKey),
6142
+ body: JSON.stringify(payload),
6143
+ signal: AbortSignal.timeout(HUB_UPLOAD_TIMEOUT_MS)
6144
+ });
6145
+ } catch (fetchError) {
6146
+ console.error("[runsec] fetch() failed \u2014 retrying Hub upload via node:http(s)");
6147
+ dumpHubNetworkError(fetchError, url);
6148
+ return postHubUploadNodeHttp(url, apiKey, payload);
6149
+ }
6150
+ }
6066
6151
  function countSeverityMetrics(findings) {
6067
6152
  const metrics = { critical: 0, high: 0, medium: 0, low: 0, total: 0 };
6068
6153
  for (const f of findings) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runsec/mcp",
3
- "version": "1.0.79",
3
+ "version": "1.0.80",
4
4
  "main": "dist/index.js",
5
5
  "files": [
6
6
  "dist",