Typosquatting Risk in Dependencies
Server depends on 'expresss' (triple s) with Levenshtein distance 1 from 'express'
How this rule decides. Each strategy below is a deterministic analysis the detector runs against the MCP server's static metadata, source code, and (when present) live connection handshake.
similarity- 1
Legitimate Fork Allowlist
legitimate-fork-allowlist - 2
Visual Confusable Replay
visual-confusable-replay - 3
Scope Squat Detection
scope-squat-detection - 4
Numeric Version Suffix Strip
numeric-version-suffix-strip - 5
Algorithm Agreement Gate
algorithm-agreement-gate
What we found. Each finding below carries a structured proof chain from source (where untrusted data enters) through propagation (how it flows) to a sink (where the dangerous operation occurs), including any mitigations checked for and the potential impact if exploited. Every link is independently verifiable against the cited location.
Proof chain
5 steps from untrusted source to potential impact. Each step is independently verifiable against the cited location.
SourceExternal Content - Where
pypi:ollama@0.4.8- Observed
Dependency pypi:ollama@0.4.8 is within Damerau-Levenshtein distance 3 of colorama (threshold 3).
- Why untrusted
- Dependency names are external content resolved from public package registries. A near-miss to a popular canonical name is a supply-chain anomaly under ISO 27001 A.5.21 — the package manager installs whichever spelling is declared, with no built-in guard against lexically similar substitutions.
PropagationDirect Pass - At
pyproject.toml/project/dependencies/ollama- Observed
The manifest entry at /project/dependencies/ollama directs the package manager to resolve and install ollama@0.4.8. Resolution is purely string-matched against the registry — a typosquatted name installs whatever code the squatter published.
SinkCommand Execution - Where
pypi:ollama@0.4.8- Observed
Malicious package `ollama` executes attacker code in the build environment or at import time. Attack classifier: levenshtein-near. Target shadowed: `colorama`.
MitigationInput ValidationAbsent - Where
pyproject.toml/project/dependencies/ollama- Detail
- Lockfiles pin versions but do not pin the spelling of the dependency name. The static analyser cannot confirm whether a typosquat-aware package firewall (Socket.dev, Snyk Advisor) is in the CI chain; the auditor must verify.
ImpactRemote Code Execution - Scope
- server-host
- Exploitability
- Trivial
- Scenario
- A developer installs `ollama` by typo, copy-paste, or autocomplete. The package's postinstall hook runs during installation with the developer's or CI runner's credentials, or the payload executes on first import when the MCP server starts. An MCP server compromised this way delegates full tool authority to attacker code on every downstream agent interaction.
- +0.1input-validation absentNo input-validation found — Lockfiles pin versions but do not pin the spelling of the dependency name. The static analyser cannot confirm whether a typosquat-aware package firewall (Socket.dev, Snyk Advisor) is in the CI chain; the auditor must verify.
- +0.1target_distance_under_thresholdDamerau-Levenshtein distance 3 between `ollama` and `colorama` is within the target's declared ceiling of 3. Combined with the Jaro-Winkler agreement check, this is the distance-only classifier — the most common class.
- +0.02algorithm_agreement_moderateJaro-Winkler similarity 0.819 clears the agreement floor (0.80) but is below the high-agreement band — the finding stands but reviewer confirmation is advised.
- -0.04legitimate_fork_allowlist_consultedThe candidate was not in legitimate-forks.ts at scan time. The rule records this explicitly so the finding can be dismissed by adding to the allowlist, with audit trail, if the reviewer confirms the dependency is a sanctioned variant.
ISO-27001-A.5.21ISO/IEC 27001:2022 Annex A Control 5.21 — ICT Supply Chain Security
A.5.21 requires processes to verify third-party suppliers and the components they deliver. A lexically near-miss dependency name is a supply-chain anomaly that the control requires be detected and reviewed before the component is accepted.
- 1
check-dependencyOpen the manifest and confirm the dependency `ollama@0.4.8` is present. The scanner's similarity pipeline matched this name against the curated target `colorama` via the levenshtein-near classifier. If this dependency is an intentional internal fork or re-export, add it to `legitimate-forks.ts` so the finding will no longer fire.
Target:
pypi:ollama@0.4.8Expect: Dependency pypi:ollama@0.4.8 is declared; it is NOT in the legitimate-fork allowlist at scan time.
- 2
check-dependencyRecompute the Damerau-Levenshtein distance and Jaro-Winkler similarity between `ollama` and `colorama` using the same primitives as the scanner. Concretely, the rule expects Damerau-Levenshtein ≤ 3 and Jaro-Winkler ≥ 0.80 (except for advisory-registry matches which skip the floor). Observed values: distance 3, Jaro-Winkler 0.819.
Target:
pypi:ollama@0.4.8Expect: Damerau-Levenshtein distance between "ollama" and "colorama" is 3. Jaro-Winkler is 0.819. The numbers agree with what the rule recorded.
- 3
check-configOpen the package manifest at this RFC 6901 pointer and read the line. Confirm the package name recorded in the manifest is literally `ollama` (not a spelling the build tool fuzzed to) and that no post-resolution rewrite turns this entry into the legitimate `colorama`.
Target:
pyproject.toml/project/dependencies/ollamaExpect: The manifest entry at pyproject.toml/project/dependencies/ollama resolves to ollama@0.4.8 — the exact name the scanner flagged.
- 4
compare-baselineOpen the PyPI page for `ollama` and compare against the legitimate `colorama`. Check: publisher identity, publish date, weekly download count, repository link, postinstall script presence. A typosquat typically presents as: recently published, low download count, no repository link, optionally carrying a postinstall hook that executes code at install time.
Target:
pypi:ollama@0.4.8Expect: Either the candidate is a legitimate publisher-authored alternative (in which case add to `legitimate-forks.ts`) or its metadata confirms the typosquat hypothesis (recent, unknown publisher, low downloads, suspicious scripts).
Proof chain
5 steps from untrusted source to potential impact. Each step is independently verifiable against the cited location.
SourceExternal Content - Where
npm:distro@1.9.0- Observed
Dependency npm:distro@1.9.0 is within Damerau-Levenshtein distance 3 of discord (threshold 3).
- Why untrusted
- Dependency names are external content resolved from public package registries. A near-miss to a popular canonical name is a supply-chain anomaly under ISO 27001 A.5.21 — the package manager installs whichever spelling is declared, with no built-in guard against lexically similar substitutions.
PropagationDirect Pass - At
package.json/dependencies/distro- Observed
The manifest entry at /dependencies/distro directs the package manager to resolve and install distro@1.9.0. Resolution is purely string-matched against the registry — a typosquatted name installs whatever code the squatter published.
SinkCommand Execution - Where
npm:distro@1.9.0- Observed
Malicious package `distro` executes attacker code in the build environment or at import time. Attack classifier: levenshtein-near. Target shadowed: `discord`.
MitigationInput ValidationAbsent - Where
package.json/dependencies/distro- Detail
- Lockfiles pin versions but do not pin the spelling of the dependency name. The static analyser cannot confirm whether a typosquat-aware package firewall (Socket.dev, Snyk Advisor) is in the CI chain; the auditor must verify.
ImpactRemote Code Execution - Scope
- server-host
- Exploitability
- Trivial
- Scenario
- A developer installs `distro` by typo, copy-paste, or autocomplete. The package's postinstall hook runs during installation with the developer's or CI runner's credentials, or the payload executes on first import when the MCP server starts. An MCP server compromised this way delegates full tool authority to attacker code on every downstream agent interaction.
- +0.1input-validation absentNo input-validation found — Lockfiles pin versions but do not pin the spelling of the dependency name. The static analyser cannot confirm whether a typosquat-aware package firewall (Socket.dev, Snyk Advisor) is in the CI chain; the auditor must verify.
- +0.1target_distance_under_thresholdDamerau-Levenshtein distance 3 between `distro` and `discord` is within the target's declared ceiling of 3. Combined with the Jaro-Winkler agreement check, this is the distance-only classifier — the most common class.
- +0.02algorithm_agreement_moderateJaro-Winkler similarity 0.848 clears the agreement floor (0.80) but is below the high-agreement band — the finding stands but reviewer confirmation is advised.
- -0.04legitimate_fork_allowlist_consultedThe candidate was not in legitimate-forks.ts at scan time. The rule records this explicitly so the finding can be dismissed by adding to the allowlist, with audit trail, if the reviewer confirms the dependency is a sanctioned variant.
ISO-27001-A.5.21ISO/IEC 27001:2022 Annex A Control 5.21 — ICT Supply Chain Security
A.5.21 requires processes to verify third-party suppliers and the components they deliver. A lexically near-miss dependency name is a supply-chain anomaly that the control requires be detected and reviewed before the component is accepted.
- 1
check-dependencyOpen the manifest and confirm the dependency `distro@1.9.0` is present. The scanner's similarity pipeline matched this name against the curated target `discord` via the levenshtein-near classifier. If this dependency is an intentional internal fork or re-export, add it to `legitimate-forks.ts` so the finding will no longer fire.
Target:
npm:distro@1.9.0Expect: Dependency npm:distro@1.9.0 is declared; it is NOT in the legitimate-fork allowlist at scan time.
- 2
check-dependencyRecompute the Damerau-Levenshtein distance and Jaro-Winkler similarity between `distro` and `discord` using the same primitives as the scanner. Concretely, the rule expects Damerau-Levenshtein ≤ 3 and Jaro-Winkler ≥ 0.80 (except for advisory-registry matches which skip the floor). Observed values: distance 3, Jaro-Winkler 0.848.
Target:
npm:distro@1.9.0Expect: Damerau-Levenshtein distance between "distro" and "discord" is 3. Jaro-Winkler is 0.848. The numbers agree with what the rule recorded.
- 3
check-configOpen the package manifest at this RFC 6901 pointer and read the line. Confirm the package name recorded in the manifest is literally `distro` (not a spelling the build tool fuzzed to) and that no post-resolution rewrite turns this entry into the legitimate `discord`.
Target:
package.json/dependencies/distroExpect: The manifest entry at package.json/dependencies/distro resolves to distro@1.9.0 — the exact name the scanner flagged.
- 4
compare-baselineOpen the npm page for `distro` and compare against the legitimate `discord`. Check: publisher identity, publish date, weekly download count, repository link, postinstall script presence. A typosquat typically presents as: recently published, low download count, no repository link, optionally carrying a postinstall hook that executes code at install time.
Target:
npm:distro@1.9.0Expect: Either the candidate is a legitimate publisher-authored alternative (in which case add to `legitimate-forks.ts`) or its metadata confirms the typosquat hypothesis (recent, unknown publisher, low downloads, suspicious scripts).
Proof chain
5 steps from untrusted source to potential impact. Each step is independently verifiable against the cited location.
SourceExternal Content - Where
npm:primp@0.15.0- Observed
Dependency npm:primp@0.15.0 is within Damerau-Levenshtein distance 2 of prisma (threshold 2).
- Why untrusted
- Dependency names are external content resolved from public package registries. A near-miss to a popular canonical name is a supply-chain anomaly under ISO 27001 A.5.21 — the package manager installs whichever spelling is declared, with no built-in guard against lexically similar substitutions.
PropagationDirect Pass - At
package.json/dependencies/primp- Observed
The manifest entry at /dependencies/primp directs the package manager to resolve and install primp@0.15.0. Resolution is purely string-matched against the registry — a typosquatted name installs whatever code the squatter published.
SinkCommand Execution - Where
npm:primp@0.15.0- Observed
Malicious package `primp` executes attacker code in the build environment or at import time. Attack classifier: levenshtein-near. Target shadowed: `prisma`.
MitigationInput ValidationAbsent - Where
package.json/dependencies/primp- Detail
- Lockfiles pin versions but do not pin the spelling of the dependency name. The static analyser cannot confirm whether a typosquat-aware package firewall (Socket.dev, Snyk Advisor) is in the CI chain; the auditor must verify.
ImpactRemote Code Execution - Scope
- server-host
- Exploitability
- Trivial
- Scenario
- A developer installs `primp` by typo, copy-paste, or autocomplete. The package's postinstall hook runs during installation with the developer's or CI runner's credentials, or the payload executes on first import when the MCP server starts. An MCP server compromised this way delegates full tool authority to attacker code on every downstream agent interaction.
- +0.1input-validation absentNo input-validation found — Lockfiles pin versions but do not pin the spelling of the dependency name. The static analyser cannot confirm whether a typosquat-aware package firewall (Socket.dev, Snyk Advisor) is in the CI chain; the auditor must verify.
- +0.1target_distance_under_thresholdDamerau-Levenshtein distance 2 between `primp` and `prisma` is within the target's declared ceiling of 2. Combined with the Jaro-Winkler agreement check, this is the distance-only classifier — the most common class.
- +0.02algorithm_agreement_moderateJaro-Winkler similarity 0.876 clears the agreement floor (0.80) but is below the high-agreement band — the finding stands but reviewer confirmation is advised.
- -0.04legitimate_fork_allowlist_consultedThe candidate was not in legitimate-forks.ts at scan time. The rule records this explicitly so the finding can be dismissed by adding to the allowlist, with audit trail, if the reviewer confirms the dependency is a sanctioned variant.
ISO-27001-A.5.21ISO/IEC 27001:2022 Annex A Control 5.21 — ICT Supply Chain Security
A.5.21 requires processes to verify third-party suppliers and the components they deliver. A lexically near-miss dependency name is a supply-chain anomaly that the control requires be detected and reviewed before the component is accepted.
- 1
check-dependencyOpen the manifest and confirm the dependency `primp@0.15.0` is present. The scanner's similarity pipeline matched this name against the curated target `prisma` via the levenshtein-near classifier. If this dependency is an intentional internal fork or re-export, add it to `legitimate-forks.ts` so the finding will no longer fire.
Target:
npm:primp@0.15.0Expect: Dependency npm:primp@0.15.0 is declared; it is NOT in the legitimate-fork allowlist at scan time.
- 2
check-dependencyRecompute the Damerau-Levenshtein distance and Jaro-Winkler similarity between `primp` and `prisma` using the same primitives as the scanner. Concretely, the rule expects Damerau-Levenshtein ≤ 2 and Jaro-Winkler ≥ 0.80 (except for advisory-registry matches which skip the floor). Observed values: distance 2, Jaro-Winkler 0.876.
Target:
npm:primp@0.15.0Expect: Damerau-Levenshtein distance between "primp" and "prisma" is 2. Jaro-Winkler is 0.876. The numbers agree with what the rule recorded.
- 3
check-configOpen the package manifest at this RFC 6901 pointer and read the line. Confirm the package name recorded in the manifest is literally `primp` (not a spelling the build tool fuzzed to) and that no post-resolution rewrite turns this entry into the legitimate `prisma`.
Target:
package.json/dependencies/primpExpect: The manifest entry at package.json/dependencies/primp resolves to primp@0.15.0 — the exact name the scanner flagged.
- 4
compare-baselineOpen the npm page for `primp` and compare against the legitimate `prisma`. Check: publisher identity, publish date, weekly download count, repository link, postinstall script presence. A typosquat typically presents as: recently published, low download count, no repository link, optionally carrying a postinstall hook that executes code at install time.
Target:
npm:primp@0.15.0Expect: Either the candidate is a legitimate publisher-authored alternative (in which case add to `legitimate-forks.ts`) or its metadata confirms the typosquat hypothesis (recent, unknown publisher, low downloads, suspicious scripts).