@runa-ai/runa-cli 0.5.33 → 0.5.35

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
@@ -925,7 +925,7 @@ var CLI_VERSION, HAS_ADMIN_COMMAND;
925
925
  var init_version = __esm({
926
926
  "src/version.ts"() {
927
927
  init_esm_shims();
928
- CLI_VERSION = "0.5.33";
928
+ CLI_VERSION = "0.5.35";
929
929
  HAS_ADMIN_COMMAND = false;
930
930
  }
931
931
  });
@@ -1722,7 +1722,8 @@ function checkBase64ForSecrets(base64String) {
1722
1722
  const decoded = Buffer.from(base64String, "base64").toString("utf-8");
1723
1723
  for (const indicator of BASE64_SECRET_INDICATORS) {
1724
1724
  if (decoded.startsWith(indicator)) {
1725
- return { found: true, decoded: `${decoded.substring(0, 20)}...` };
1725
+ const secretType = getSecretTypeFromIndicator(indicator);
1726
+ return { found: true, secretType };
1726
1727
  }
1727
1728
  }
1728
1729
  return { found: false };
@@ -1730,6 +1731,18 @@ function checkBase64ForSecrets(base64String) {
1730
1731
  return { found: false };
1731
1732
  }
1732
1733
  }
1734
+ function getSecretTypeFromIndicator(indicator) {
1735
+ const indicatorMap = {
1736
+ "sk-": "OpenAI/Stripe API key",
1737
+ ghp_: "GitHub Personal Access Token",
1738
+ gho_: "GitHub OAuth Token",
1739
+ AKIA: "AWS Access Key",
1740
+ eyJ: "JWT Token",
1741
+ vercel_: "Vercel Token",
1742
+ sbp_: "Supabase Token"
1743
+ };
1744
+ return indicatorMap[indicator] ?? "Unknown secret type";
1745
+ }
1733
1746
  function isCommentLine(line) {
1734
1747
  const trimmed = line.trim();
1735
1748
  return trimmed.startsWith("//") || trimmed.startsWith("#") || trimmed.startsWith("*") || trimmed.startsWith("/*") || trimmed.startsWith("<!--") || trimmed.startsWith("--");
@@ -1982,7 +1995,7 @@ function scanLineForSecrets(line, lineNumber, filePath) {
1982
1995
  ruleId: "secret/base64-encoded",
1983
1996
  severity: "high",
1984
1997
  title: "Base64-Encoded Secret",
1985
- description: `Base64-encoded secret detected. Decoded prefix: ${result.decoded}`,
1998
+ description: `Base64-encoded secret detected. Type: ${result.secretType}`,
1986
1999
  location: {
1987
2000
  file: filePath,
1988
2001
  line: lineNumber,
@@ -3362,6 +3375,14 @@ var init_json_reporter = __esm({
3362
3375
  });
3363
3376
 
3364
3377
  // src/internal/vuln-checker/reporters/markdown-reporter.ts
3378
+ function escapeMarkdown(text) {
3379
+ let escaped = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3380
+ escaped = escaped.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\*/g, "\\*").replace(/_/g, "\\_").replace(/\{/g, "\\{").replace(/\}/g, "\\}").replace(/\[/g, "\\[").replace(/\]/g, "\\]").replace(/\(/g, "\\(").replace(/\)/g, "\\)").replace(/#/g, "\\#").replace(/\+/g, "\\+").replace(/-/g, "\\-").replace(/\./g, "\\.").replace(/!/g, "\\!").replace(/\|/g, "\\|");
3381
+ return escaped;
3382
+ }
3383
+ function sanitizeCodeBlock(text) {
3384
+ return text.replace(/```/g, "\\`\\`\\`");
3385
+ }
3365
3386
  function groupByCategory2(findings) {
3366
3387
  const byCategory = /* @__PURE__ */ new Map();
3367
3388
  for (const finding of findings) {
@@ -3392,29 +3413,31 @@ function formatMetadata(finding) {
3392
3413
  }
3393
3414
  function formatSnippet(finding) {
3394
3415
  if (!finding.snippet) return [];
3395
- return ["```", finding.snippet.text, "```\n"];
3416
+ return ["```", sanitizeCodeBlock(finding.snippet.text), "```\n"];
3396
3417
  }
3397
3418
  function formatFix(finding) {
3398
3419
  if (!finding.fix) return [];
3399
- const lines = [`**Fix**: ${finding.fix.description}
3420
+ const lines = [`**Fix**: ${escapeMarkdown(finding.fix.description)}
3400
3421
  `];
3401
3422
  if (finding.fix.replacement) {
3402
- lines.push("```", finding.fix.replacement, "```\n");
3423
+ lines.push("```", sanitizeCodeBlock(finding.fix.replacement), "```\n");
3403
3424
  }
3404
3425
  return lines;
3405
3426
  }
3406
3427
  function formatFinding2(finding) {
3407
3428
  const emoji = SEVERITY_EMOJI[finding.severity];
3408
3429
  const location = `${formatFilePath(finding.location.file)}:${finding.location.line}`;
3430
+ const safeTitle = escapeMarkdown(finding.title);
3431
+ const safeDescription = escapeMarkdown(finding.description);
3409
3432
  return [
3410
- `#### ${emoji} ${finding.title}
3433
+ `#### ${emoji} ${safeTitle}
3411
3434
  `,
3412
3435
  `- **Severity**: ${finding.severity}`,
3413
3436
  `- **Location**: \`${location}\``,
3414
3437
  `- **Rule**: \`${finding.ruleId}\``,
3415
3438
  ...formatMetadata(finding),
3416
3439
  `
3417
- ${finding.description}
3440
+ ${safeDescription}
3418
3441
  `,
3419
3442
  ...formatSnippet(finding),
3420
3443
  ...formatFix(finding),
@@ -3483,8 +3506,9 @@ var init_markdown_reporter = __esm({
3483
3506
  lines.push("The following findings were ignored based on configuration:\n");
3484
3507
  for (const finding of result.ignoredFindings) {
3485
3508
  const emoji = SEVERITY_EMOJI[finding.severity];
3509
+ const safeTitle = escapeMarkdown(finding.title);
3486
3510
  lines.push(
3487
- `- ${emoji} **${finding.title}** at \`${finding.location.file}:${finding.location.line}\``
3511
+ `- ${emoji} **${safeTitle}** at \`${finding.location.file}:${finding.location.line}\``
3488
3512
  );
3489
3513
  }
3490
3514
  lines.push("");
@@ -1 +1 @@
1
- {"version":3,"file":"secret-analyzer.d.ts","sourceRoot":"","sources":["../../../../src/internal/vuln-checker/analyzers/secret-analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,OAAO,EAAoB,MAAM,aAAa,CAAC;AAgiClG;;GAEG;AACH,qBAAa,cAAe,YAAW,QAAQ;IAC7C,IAAI,SAAoB;IACxB,UAAU,EAAE,QAAQ,EAAE,CAAc;IAE9B,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;YAkB7C,cAAc;IAY5B,OAAO,CAAC,UAAU;CAGnB"}
1
+ {"version":3,"file":"secret-analyzer.d.ts","sourceRoot":"","sources":["../../../../src/internal/vuln-checker/analyzers/secret-analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,OAAO,EAAoB,MAAM,aAAa,CAAC;AA2jClG;;GAEG;AACH,qBAAa,cAAe,YAAW,QAAQ;IAC7C,IAAI,SAAoB;IACxB,UAAU,EAAE,QAAQ,EAAE,CAAc;IAE9B,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;YAkB7C,cAAc;IAY5B,OAAO,CAAC,UAAU;CAGnB"}
@@ -1,5 +1,8 @@
1
1
  /**
2
2
  * Markdown reporter for human-readable vulnerability reports
3
+ *
4
+ * SECURITY (Issue #543): This reporter sanitizes all user-controlled content
5
+ * to prevent XSS and injection attacks when reports are rendered in web interfaces.
3
6
  */
4
7
  import type { Reporter, ScanResult } from '../types.js';
5
8
  export declare class MarkdownReporter implements Reporter {
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-reporter.d.ts","sourceRoot":"","sources":["../../../../src/internal/vuln-checker/reporters/markdown-reporter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAW,QAAQ,EAAE,UAAU,EAAY,MAAM,aAAa,CAAC;AAgH3E,qBAAa,gBAAiB,YAAW,QAAQ;IAC/C,IAAI,SAAc;IAElB,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM;CAqDnC"}
1
+ {"version":3,"file":"markdown-reporter.d.ts","sourceRoot":"","sources":["../../../../src/internal/vuln-checker/reporters/markdown-reporter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAW,QAAQ,EAAE,UAAU,EAAY,MAAM,aAAa,CAAC;AA2K3E,qBAAa,gBAAiB,YAAW,QAAQ;IAC/C,IAAI,SAAc;IAElB,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM;CAuDnC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runa-ai/runa-cli",
3
- "version": "0.5.33",
3
+ "version": "0.5.35",
4
4
  "private": false,
5
5
  "description": "AI-powered DevOps CLI",
6
6
  "type": "module",
@@ -53,7 +53,7 @@
53
53
  "xstate": "5.25.0",
54
54
  "zod": "4.3.5",
55
55
  "@runa-ai/runa": "0.5.33",
56
- "@runa-ai/runa-xstate-test-plugin": "0.5.28"
56
+ "@runa-ai/runa-xstate-test-plugin": "0.5.35"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">=20.0.0"