Tool Poisoning

1 findingMCP02ASI02CoSAI-T4CoSAI-T6CoSAI-T9MAESTRO-L3MAESTRO-L7EU-AI-Act-Art-13AML.T0058#

Deceptive Naming

1 finding
F5

Official Namespace Squatting

CriticalMCP02-tool-poisoningAML.T0054

Server published as '@anthropic-tools/filesystem' by an unverified author not in the anthropics GitHub org

  1. 1Compare the observed server name "@aaronsb/google-workspace-mcp" against the vendor namespace "google" (Google). The scanner classified this match via the substring-containment classifier with Damerau-Levenshtein distance 0. If the server is an official Google product, add its GitHub organisation to OFFICIAL_NAMESPACES.verified_github_orgs in the rule's data file.initialize.server_nameExpect: Server name "@aaronsb/google-workspace-mcp" directly contains the vendor token "google".
  2. 2Open the server's repository at https://github.com/aaronsb/google-workspace-mcp and confirm the owning organisation is NOT one of the vendor's verified orgs. The vendor registers the following orgs as authoritative: github.com/google/…, github.com/googleapis/…, github.com/google-gemini/…. A match against any of these suppresses the finding.initialize.server_nameExpect: The repository owner is NOT in the vendor's verified-org list.
  3. 3Open the MCP registry page for "@aaronsb/google-workspace-mcp" (Smithery, PulseMCP, or modelcontextprotocol.io/registry). Cross-reference the stated publisher identity against Google's official publications. A recently published server with low install count and no vendor affiliation is the canonical squat pattern.initialize.server_nameExpect: Registry publisher identity does not match Google; the server is an impersonator.
sourceexternal-content
initialize.server_name
Server name "@aaronsb/google-workspace-mcp" matches Google namespace "google" via substring containment.

The MCP client surfaces the server name verbatim in its approval dialog, and the LLM ingests the server name alongside the tool descriptions. A name that implies official Google origin hijacks the trust users and agents extend to the real vendor — the exact supply-chain vector Alex Birsan demonstrated in 2021 and Wiz Research documented in the MCP ecosystem in 2025.

propagationcross-tool-flow
capability:tools
Publisher URL "https://github.com/aaronsb/google-workspace-mcp" is NOT under any of Google's verified GitHub organisations (google, googleapis, google-gemini). The server name + publisher mismatch propagates misplaced trust to every downstream tool invocation.
sinkprivilege-grant
initialize.server_name
Users approve the server on the basis of the vendor-branded name, granting it the session-scoped trust they would extend to a genuine Google product. All subsequent tool calls execute under that elevated trust.
impactcross-agent-propagation
ai-client

User installs "@aaronsb/google-workspace-mcp" believing it is an official Google MCP server. The LLM consumes the impersonator's tool descriptions, instructions, and output under the vendor's brand halo. Subsequent prompt injection, credential harvesting, or data exfiltration by the impersonator inherits the vendor's trust across every conversation that uses the tool.

trivial
Confidence90%OWASP-MCP10-Supply-ChainOWASP MCP Top 10 — MCP10 Supply Chain
3 confidence factors
  • +0.2official_namespace_signalServer name contains the vendor token "google" verbatim and the repository is NOT under any of the vendor's verified GitHub organisations. Direct containment is the highest-confidence classifier.
  • +0.08publisher_url_mismatchPublisher URL "https://github.com/aaronsb/google-workspace-mcp" is NOT under any of Google's verified GitHub organisations (google, googleapis, google-gemini). Publisher mismatch + namespace match is the canonical squat signature.
  • -0.08charter_confidence_capF5 charter caps confidence at 0.9 — namespace similarity + publisher mismatch is strong but not definitive. Vendor-approved partners may use the vendor namespace without a verified_github_org match, and the rule's curated vendor-org list can lag behind a rename. The 0.10 gap signals "strong static evidence, reviewer corroborates publisher identity".
Methodology5 tests · 4 frameworks
Technique
similarity
Tests (5)
  1. levenshtein-distance-band
  2. visual-confusable-replay
  3. substring-containment-check
  4. publisher-url-verification
  5. unicode-normalisation
Lethal edge cases (6)
  • Damerau-Levenshtein distance 1 from an official vendor name — "anthropc", "googl", "microsft" are typosquats a reviewer would read past. The rule must flag these at the highest confidence band: edit-distance-one from a high-value namespace is a dominant supply-chain signal.
  • Visual-confusable substitution — "l" → "1" ("goog1e"), "o" → "0" ("micr0soft"), "I" → "l" ("lBM") — distance-2 in byte space but visually indistinguishable in a monospaced approval dialog. The rule must apply the same visual-confusable replay as D3 to catch these without requiring a curated list of every visual variant.
  • Substring containment without an official repository link — a server named "anthropic-filesystem-mcp" contains "anthropic" verbatim. If the github_url is not under github.com/anthropics/, the server is impersonating the namespace regardless of the owner's intent (accidental squats are still squats, because the trust they hijack is real).
  • Legitimate impersonation — a third-party server that IS an officially-approved partner of the vendor (think: Anthropic Marketplace partners). The rule cannot distinguish approved partners from squatters statically; it emits the finding and documents the no_publisher_match signal so a reviewer can dismiss with organisational context.
  • Homoglyph attack — Cyrillic "а" (U+0430) inside "аnthropic" renders identically to Latin "a" (U+0061) in most terminal fonts. The rule must normalise Unicode confusables before similarity comparison (shared with D3's Unicode path) so the homoglyph variant does not silently evade the check.
  • Plural/possessive — "anthropics-mcp" (the real Anthropic GitHub org is `anthropics`) versus "anthropic-mcp" (singular, shared with the company brand). Both land inside distance-1 of the other; the rule must not flag `anthropics` as a squat of `anthropic` when the github_url confirms the legitimate org.
Confidence cap
unbounded
Frameworks (4)
  • EU AI ActArt.13Transparency & Provision of Information to Deployers
  • OWASP MCPMCP02Tool Poisoning
  • OWASP MCPMCP10Supply Chain Compromise
  • OWASP ASIASI04Agentic Supply Chain
Backing
  • Precision:
  • Recall:
  • Red-team fixtures: 4
  • CVE replays: none
  • Last validated:

Supply Chain Security

1 findingMCP08MCP10ASI04CoSAI-T6CoSAI-T8CoSAI-T11MAESTRO-L4EU-AI-Act-Art-9AML.T0017#

Malicious & Typosquat Packages

1 finding
D3

Typosquatting Risk in Dependencies

HighMCP10-supply-chain

Server depends on 'expresss' (triple s) with Levenshtein distance 1 from 'express'

  1. 1Open the manifest and confirm the dependency `yaml@2.8.2` is present. The scanner's similarity pipeline matched this name against the curated target `pyyaml` 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.pypi:yaml@2.8.2Expect: Dependency pypi:yaml@2.8.2 is declared; it is NOT in the legitimate-fork allowlist at scan time.
  2. 2Recompute the Damerau-Levenshtein distance and Jaro-Winkler similarity between `yaml` and `pyyaml` 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.889.pypi:yaml@2.8.2Expect: Damerau-Levenshtein distance between "yaml" and "pyyaml" is 2. Jaro-Winkler is 0.889. The numbers agree with what the rule recorded.
  3. 3Open the package manifest at this RFC 6901 pointer and read the line. Confirm the package name recorded in the manifest is literally `yaml` (not a spelling the build tool fuzzed to) and that no post-resolution rewrite turns this entry into the legitimate `pyyaml`.pyproject.toml/project/dependencies/yamlExpect: The manifest entry at pyproject.toml/project/dependencies/yaml resolves to yaml@2.8.2 — the exact name the scanner flagged.
  4. 4Open the PyPI page for `yaml` and compare against the legitimate `pyyaml`. 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.pypi:yaml@2.8.2Expect: 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).
sourceexternal-content
pypi:yaml@2.8.2
Dependency pypi:yaml@2.8.2 is within Damerau-Levenshtein distance 2 of pyyaml (threshold 2).

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
pyproject.toml/project/dependencies/yaml
The manifest entry at /project/dependencies/yaml directs the package manager to resolve and install yaml@2.8.2. Resolution is purely string-matched against the registry — a typosquatted name installs whatever code the squatter published.
sinkcommand-execution
pypi:yaml@2.8.2
Malicious package `yaml` executes attacker code in the build environment or at import time. Attack classifier: levenshtein-near. Target shadowed: `pyyaml`.
mitigationinput-validationabsent
pyproject.toml/project/dependencies/yaml

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
server-host

A developer installs `yaml` 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.

trivial
Confidence88%ISO-27001-A.5.21ISO/IEC 27001:2022 Annex A Control 5.21 — ICT Supply Chain Security
4 confidence factors
  • +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 `yaml` and `pyyaml` 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.889 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.
Methodology5 tests · 4 frameworks
Technique
similarity
Tests (5)
  1. legitimate-fork-allowlist
  2. visual-confusable-replay
  3. scope-squat-detection
  4. numeric-version-suffix-strip
  5. algorithm-agreement-gate
Lethal edge cases (7)
  • Legitimate namespace fork — `lodash-es` is a real package within Damerau-Levenshtein distance 3 of `lodash`. A detector that fires purely on edit distance misclassifies it as a typosquat. The rule suppresses candidates listed in `legitimate-forks.ts` and down-weights candidates whose only extra content is a structural suffix like `-es`, `-fork`, `-pro`.
  • Visual-confusable graphemes in ASCII — `rnistral` differs from `mistral` by substituting `rn` for `m`. Pure Damerau-Levenshtein scores distance 2 but doesn't flag this as "near" `mistral` with high confidence. The rule re-evaluates every <=2-distance candidate through `visuallyConfusableVariants` to catch the RN/M, CL/D, VV/W cohort.
  • Scope-squat under a different scope — `@mcp/sdk` shadows the official `@modelcontextprotocol/sdk` via scope replacement rather than substring edits. Character-level Levenshtein would consider these far apart. The rule runs a scope-squat check on any dependency whose UNSCOPED tail matches the tail of a `scoped_official` target but whose scope differs (including no-scope).
  • Version-suffixed package — `react-18`, `webpack-5`, `python-3.12`. These are legitimate publisher-versioned aliases and must not be flagged. The rule treats numeric suffixes separated by `-` or `.` as non-material for the similarity comparison — the suffix is stripped before Damerau-Levenshtein evaluation.
  • Deprecated-official official rename — `request` is deprecated in favour of `got`, yet `request` remains a published package and many legacy servers still depend on it. The rule must NOT flag `request` as a typosquat of `got` (distance-wise these are far apart anyway, but the rule nonetheless documents this class to acknowledge the failure mode).
  • Author-internal name coinciding with a public near-miss — an org's private package `@acme/requestss` is three edits from public `requests`. The rule cannot distinguish private from public registries statically; it emits the finding with a `no_confirmed_malicious_record` factor (negative adjustment) so the reviewer sees that the finding is distance-only and can apply organisational context to dismiss.
  • Short-name collisions — `axios` has length 5. A Damerau-Levenshtein distance of 2 against `axios` produces many legitimate 3-5 character unrelated names (e.g. a greenfield utility called `axles`). The rule uses the target's declared `max_distance` (2 for short names, 3 for longer) and additionally requires a Jaro-Winkler similarity ≥ 0.80 before firing — agreement between two complementary algorithms is the filter against single-algorithm noise.
Confidence cap
unbounded
Frameworks (4)
  • EU AI ActArt.9Risk Management System
  • OWASP MCPMCP08Dependency Vulnerabilities
  • OWASP MCPMCP10Supply Chain Compromise
  • OWASP ASIASI04Agentic Supply Chain
Backing
  • Precision:
  • Recall:
  • Red-team fixtures: 4
  • CVE replays: none
  • Last validated:

Tested cleanly

  • Prompt Injection24 rules tested cleanly
  • Code Vulnerabilities23 rules tested cleanly
  • Data Exfiltration15 rules tested cleanly
  • Authentication & Identity9 rules tested cleanly
  • Human Oversight6 rules tested cleanly
  • Audit & Logging5 rules tested cleanly
  • Multi-Agent Security1 rule tested cleanly
  • Protocol & Transport15 rules tested cleanly
  • Denial of Service7 rules tested cleanly
  • Container & Runtime10 rules tested cleanly
  • Model Manipulation8 rules tested cleanly
@aaronsb/google-workspace-mcp security findings — MCP Sentinel