Skip to content

fix(supply-chain): relative edit distance for SC6 typosquat detection - #104

Merged
rng1995 merged 1 commit into
NVIDIA:mainfrom
yonatangross:fix/sc6-typosquat-relative-distance
Jun 22, 2026
Merged

rng1995 merged 1 commit into
NVIDIA:mainfrom
yonatangross:fix/sc6-typosquat-relative-distance

Conversation

@yonatangross

Copy link
Copy Markdown

What

Fixes one of the false positives reported in #103: SC6 typosquat detection
uses an absolute edit-distance threshold of 2, which collides on short,
legitimate package names. task is a real package and is edit-distance 2
from flask, so it was flagged as a "possible typosquat".

Fix

Add a relative-distance guard to _is_typosquat: a genuine typosquat perturbs
only a small fraction of the name, so require dist / shorter_len <= 1/3.
Short names then need an all-but-one-character match, while longer names may
still differ by two characters.

candidate → popular len dist before after
reqeusts → requests 8 2 flag flag (unchanged)
expreess → express 7/8 1 flag flag (unchanged)
task → flask 4/5 2 flag not flagged (FP fixed)

Test plan

  • Added a regression test (test_is_typosquat_short_distinct_name_not_flagged)
    asserting task/flask is not flagged while reqeusts/requests still is.
  • pytest tests/unit/test_patterns_new.py — 177 passed (all existing
    SC4/SC5/SC6 assertions preserved).
  • End-to-end: scanning a package.json with task + expreess deps now
    reports SC6 for expreess only.
  • ruff check src/ tests/ clean.

Signed off per DCO. Refs #103.

…etection

Absolute edit-distance <= 2 produces false positives on short, legitimate
package names: "task" is a real package and is edit-distance 2 from "flask",
yet was flagged as a possible typosquat (one of the cases reported in NVIDIA#103).

Add a relative-distance guard (dist/shorter_len <= 1/3) so short names need an
all-but-one-character match while longer names may still differ by two
characters. Existing behaviour is preserved:
  - "reqeusts" -> "requests" (len 8, dist 2) still flagged
  - "expreess" -> "express"  (dist 1)         still flagged
  - "task"     -> "flask"    (len 4, dist 2)  no longer flagged

Adds a regression test; all existing SC4/SC5/SC6 unit tests still pass and
ruff is clean.

Refs NVIDIA#103

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Yonatan Gross <[email protected]>

@rng1995 rng1995 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sensible improvement to cut typosquat false positives. Approving.

The relative-distance guard (dist * 3 > shorter -> continue, i.e. require edit-distance ≤ ⅓ of the shorter name) correctly distinguishes real short packages from typosquats: task vs flask (distance 2 on a 4-char name) is no longer flagged, while reqeusts vs requests (distance 2 on 8 chars) still is. The comment explaining the rationale is appreciated, and the regression test pins both cases.

Minor / optional (non-blocking): this does reduce recall for short popular names — a 2-edit squat against a ≤5-char target (e.g. a 5-char package) won't trip the absolute-≤2 path anymore, only 1-edit squats will. That's a reasonable precision/recall tradeoff and is well documented, just flagging it for awareness.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants