@clear-capabilities/agentic-security-scanner 0.140.0 → 0.141.0

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 (62) hide show
  1. package/CHANGELOG.md +148 -0
  2. package/dist/113.index.js +79 -3
  3. package/dist/178.index.js +1 -1
  4. package/dist/238.index.js +77 -1
  5. package/dist/384.index.js +1 -1
  6. package/dist/435.index.js +12 -0
  7. package/dist/526.index.js +79 -3
  8. package/dist/637.index.js +1 -1
  9. package/dist/agentic-security.mjs +14 -14
  10. package/dist/agentic-security.mjs.sha256 +1 -1
  11. package/dist/compliance-frameworks/ccpa.json +34 -7
  12. package/dist/compliance-frameworks/eu-ai-act.json +65 -14
  13. package/dist/compliance-frameworks/gdpr.json +56 -12
  14. package/dist/compliance-frameworks/hipaa-security-rule.json +68 -15
  15. package/dist/compliance-frameworks/nist-ai-600-1.json +57 -12
  16. package/dist/compliance-frameworks/nist-csf-2.json +78 -16
  17. package/dist/compliance-frameworks/nist-privacy-1-1.json +3 -0
  18. package/dist/compliance-frameworks/owasp-asvs-5.json +91 -20
  19. package/dist/compliance-frameworks/owasp-llm-top-10.json +89 -20
  20. package/package.json +16 -5
  21. package/src/dataflow/catalog.js +61 -0
  22. package/src/engine.js +262 -22
  23. package/src/mcp/tools.js +12 -0
  24. package/src/posture/accuracy-scorecard.js +57 -0
  25. package/src/posture/aibom.js +110 -1
  26. package/src/posture/auditor-walkthrough.js +56 -17
  27. package/src/posture/compliance-frameworks/ccpa.json +34 -7
  28. package/src/posture/compliance-frameworks/eu-ai-act.json +65 -14
  29. package/src/posture/compliance-frameworks/gdpr.json +56 -12
  30. package/src/posture/compliance-frameworks/hipaa-security-rule.json +68 -15
  31. package/src/posture/compliance-frameworks/nist-ai-600-1.json +57 -12
  32. package/src/posture/compliance-frameworks/nist-csf-2.json +78 -16
  33. package/src/posture/compliance-frameworks/nist-privacy-1-1.json +3 -0
  34. package/src/posture/compliance-frameworks/owasp-asvs-5.json +91 -20
  35. package/src/posture/compliance-frameworks/owasp-llm-top-10.json +89 -20
  36. package/src/posture/concurrency-checker.js +3 -3
  37. package/src/posture/coverage-strength.js +182 -0
  38. package/src/posture/epss.js +17 -1
  39. package/src/posture/family-registry.js +103 -0
  40. package/src/posture/family-resolve.js +47 -0
  41. package/src/posture/fix-coverage.js +113 -0
  42. package/src/posture/fix-metrics.js +76 -0
  43. package/src/posture/mcp-rug-pull.js +144 -0
  44. package/src/posture/poc-inprocess.js +217 -1
  45. package/src/posture/proof-coverage.js +162 -0
  46. package/src/posture/reachability-filter.js +44 -0
  47. package/src/posture/sbom.js +12 -3
  48. package/src/runScan.js +56 -5
  49. package/src/sast/CLAUDE.md +2 -2
  50. package/src/sast/claude-md-prompt-injection.js +47 -3
  51. package/src/sast/cloud-iam.js +23 -0
  52. package/src/sast/convention-deviation.js +66 -3
  53. package/src/sast/crypto-protocol.js +23 -0
  54. package/src/sast/dapp-frontend.js +20 -0
  55. package/src/sast/iac-cloud-templates.js +337 -0
  56. package/src/sast/k8s-admission.js +27 -0
  57. package/src/sast/ml-supply-chain.js +22 -0
  58. package/src/sast/ruby.js +132 -0
  59. package/src/sast/web3-advanced.js +26 -0
  60. package/src/sca/CLAUDE.md +21 -4
  61. package/src/sca/container.js +18 -1
  62. package/src/sca/dep-confusion.js +69 -3
@@ -1,6 +1,10 @@
1
1
  // 0.9.0 Feat-15: Dependency confusion + typosquat detection (Levenshtein distance against top-1000 npm/PyPI packages).
2
2
  //
3
- // (a) Typosquat: Levenshtein distance 1–2 from a popular package.
3
+ // (a) Typosquat: a small Damerau-Levenshtein distance from a popular package,
4
+ // where "small" is judged RELATIVE to the name length — see SIMILARITY
5
+ // below for why the absolute 1–2 this originally used produced 166
6
+ // critical/high false positives and zero true positives across 13 real
7
+ // dependency trees.
4
8
  // (b) Confusion: internal-scoped names (`@your-org/...`) that also appear on the
5
9
  // public registry — declared via .agentic-security/internal-scopes.yml.
6
10
  //
@@ -50,6 +54,64 @@ export function levenshtein(a, b, maxDistance = 2) {
50
54
  return prev[b.length];
51
55
  }
52
56
 
57
+ // Damerau-Levenshtein (optimal string alignment): a TRANSPOSITION costs 1.
58
+ //
59
+ // Plain Levenshtein charges 2 for a transposition, which is exactly backwards
60
+ // for this problem — swapping two adjacent characters (`lodahs` for `lodash`,
61
+ // `electorn` for `electron`) is the single most common real typo, and it is the
62
+ // one plain distance scores as least similar. `levenshtein` above is kept
63
+ // unchanged and separately tested; this is a second measure for a different
64
+ // question.
65
+ export function damerauLevenshtein(a, b, maxDistance = 2) {
66
+ if (a === b) return 0;
67
+ if (Math.abs(a.length - b.length) > maxDistance) return maxDistance + 1;
68
+ const m = a.length, n = b.length;
69
+ if (!m) return n;
70
+ if (!n) return m;
71
+ const d = Array.from({ length: m + 1 }, (_, i) => {
72
+ const row = new Array(n + 1).fill(0);
73
+ row[0] = i;
74
+ return row;
75
+ });
76
+ for (let j = 0; j <= n; j++) d[0][j] = j;
77
+ for (let i = 1; i <= m; i++) {
78
+ let rowMin = Infinity;
79
+ for (let j = 1; j <= n; j++) {
80
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
81
+ let v = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
82
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
83
+ v = Math.min(v, d[i - 2][j - 2] + 1); // transposition
84
+ }
85
+ d[i][j] = v;
86
+ if (v < rowMin) rowMin = v;
87
+ }
88
+ if (rowMin > maxDistance) return maxDistance + 1;
89
+ }
90
+ return d[m][n];
91
+ }
92
+
93
+ // How much of a name may differ before it is a DIFFERENT name rather than a
94
+ // misspelling of this one.
95
+ //
96
+ // Measured, not chosen by taste. At the previous "distance 1–2, any length"
97
+ // rule, bench/sca-replay produced these across 13 real repositories:
98
+ //
99
+ // ms ~ ws (d1) acorn ~ cors (d2) ajv ~ ava (d2) six ~ tox (d2)
100
+ // abab ~ ava (d2) arg ~ yargs (d2) bail ~ babel (d2) aws4 ~ ws (d2)
101
+ //
102
+ // Every one is a legitimate, popular package, and `ms` is a top-50 npm
103
+ // package. The common factor is length: two edits on a four-character name
104
+ // changes half of it. A quarter of the shorter name is the ceiling — it keeps
105
+ // every genuine shape (one transposition, one dropped char, one doubled char
106
+ // on a name of ordinary length) and rejects all of the above.
107
+ const MAX_DIVERGENCE = 0.25;
108
+
109
+ function _isTyposquatCandidate(name, popular, distance) {
110
+ if (distance <= 0) return false;
111
+ const shorter = Math.min(name.length, popular.length);
112
+ return distance / shorter <= MAX_DIVERGENCE;
113
+ }
114
+
53
115
  function _loadInternalScopes(scanRoot) {
54
116
  if (!scanRoot) return [];
55
117
  for (const name of ['internal-scopes.yml', 'internal-scopes.yaml']) {
@@ -84,10 +146,14 @@ export function detectDepConfusion(components, scanRoot) {
84
146
  const lowerName = c.name.toLowerCase();
85
147
  // (1) Typosquat — only run if the dep is NOT itself in the popular set
86
148
  if (!popularSet.has(lowerName)) {
149
+ // Compare the BARE name. `@scope/react` is not a typosquat of `react`;
150
+ // the scope is the thing that identifies the publisher.
151
+ const bare = lowerName.replace(/^@[^/]+\//, '');
87
152
  let bestMatch = null, bestDist = 3;
88
153
  for (const popular of popularSet) {
89
- const d = levenshtein(lowerName, popular, 2);
90
- if (d > 0 && d <= 2 && d < bestDist) { bestMatch = popular; bestDist = d; }
154
+ const d = damerauLevenshtein(bare, popular, 2);
155
+ if (!_isTyposquatCandidate(bare, popular, d)) continue;
156
+ if (d < bestDist) { bestMatch = popular; bestDist = d; }
91
157
  }
92
158
  if (bestMatch) {
93
159
  const id = `dep-confusion:${c.ecosystem}:${c.name}@${c.version}:typosquat`;