ktg-plugin-marketplace/plugins/llm-security/tests/lib
Kjell Tore Guttormsen 5f8f2d3c41 fix(dep): B7 — token-overlap typosquat heuristic alongside Levenshtein
Critical-review §2 B7 finding: pure Levenshtein <=2 misses the most common
modern typosquat pattern — popular-name + token-injection suffix. Examples:
  lodash → lodash-utils    (edit distance 6, not flagged pre-B7)
  react  → react-helper    (edit distance 7, not flagged pre-B7)
  express → express-wrapper (edit distance 8, not flagged pre-B7)

Three coordinated edits:

scanners/lib/string-utils.mjs
- Adds tokenize(name): string[]    splits on -/_, lowercases
- Adds tokenOverlap(a, b): number  intersection.size / min(|a|,|b|)
- Adds TYPOSQUAT_SUSPICIOUS_TOKENS frozen list of common typosquat
  suffixes. Excludes language-extension tokens (js, jsx, ts, tsx) — the
  v7.0.0 allowlist contains `tsx` as a legit package and including the
  same token in the suspicious set creates a contradiction. Caught by
  the new allowlist-intersection-guard test. Also excludes 'pro'
  (legitimate edition marker).

scanners/dep-auditor.mjs + scanners/supply-chain-recheck.mjs
- New checkTyposquatTokenOverlap() helper — fires AFTER Levenshtein 1/2
  branches, only when:
    1. popular package's tokens ⊆ declared name's tokens (strict superset)
    2. declared name has at least one suspicious suffix
    3. popular package is in topCutoff window
  All three conditions required — conservative by design. Allowlist
  precedence preserved (existing 22 npm + 13 PyPI entries always pass).
  MEDIUM severity, NOT block. New finding title prefix:
  "Possible typosquatting via token-overlap".

Tests: +21 cases across two new files
- tests/lib/string-utils-tokens.test.mjs (15) — tokenize, tokenOverlap,
  TYPOSQUAT_SUSPICIOUS_TOKENS frozen contract, allowlist-intersection
  guard (caught the tsx conflict on first run)
- tests/scanners/dep-token-overlap.test.mjs (7) — integration via
  in-memory tmpdir fixtures: lodash-utils flagged, react-helper flagged,
  express-wrapper flagged, lodash exact NOT flagged, allowlist tools
  (knip/tsx/nx/rimraf) NOT flagged, react-router-dom (no suspicious
  suffix) NOT flagged, react itself (equal token set, not superset)
  NOT flagged.

Existing dep.test.mjs and supply-chain-recheck.test.mjs unchanged —
all green (149 → 149 regression guard).

Suite: 1570 → 1591 (+21). All green.
2026-04-29 14:10:53 +02:00
..
audit-trail.test.mjs feat(governance): add structured JSONL audit trail with SIEM-ready schema 2026-04-10 13:25:59 +02:00
bash-normalize.test.mjs feat: initial open marketplace with llm-security, config-audit, ultraplan-local 2026-04-06 18:47:49 +02:00
build-zip.mjs feat(llm-security): /security ide-scan <url> — Marketplace/OpenVSX/direct VSIX (v6.4.0) 2026-04-17 17:16:26 +02:00
distribution-stats.test.mjs feat: initial open marketplace with llm-security, config-audit, ultraplan-local 2026-04-06 18:47:49 +02:00
doc-consistency.test.mjs docs(scoring): unify scan/audit/mcp-scanner/posture-assessor to v2 formula 2026-04-29 13:58:25 +02:00
git-clone-sandbox.test.mjs feat(llm-security): sandboxed remote cloning v5.1.0 2026-04-07 17:08:32 +02:00
injection-patterns.test.mjs feat: initial open marketplace with llm-security, config-audit, ultraplan-local 2026-04-06 18:47:49 +02:00
mcp-description-cache.test.mjs feat: initial open marketplace with llm-security, config-audit, ultraplan-local 2026-04-06 18:47:49 +02:00
output.test.mjs feat(llm-security)!: v7.0.0 commit 6 — tests, docs, version bump 2026-04-19 22:26:35 +02:00
policy-loader.test.mjs feat(ci): add CI/CD integration — --fail-on, --compact, pipeline templates 2026-04-10 14:59:05 +02:00
severity.test.mjs docs(severity): B3 — document info as scoring-inert (v7.2.0 prep) 2026-04-29 13:56:11 +02:00
string-utils-tokens.test.mjs fix(dep): B7 — token-overlap typosquat heuristic alongside Levenshtein 2026-04-29 14:10:53 +02:00
string-utils.test.mjs feat: initial open marketplace with llm-security, config-audit, ultraplan-local 2026-04-06 18:47:49 +02:00