Back to skill

Security audit

mcp-sanctions-check

Security checks for vulnerabilities and agentic risk

Overview

This sanctions-checking skill appears purpose-aligned, but its unpinned npm execution, package identity mismatch, and weak cache/data-source handling create review-worthy supply-chain and compliance-integrity risks.

Install only after reviewing the package source and preferably pinning the exact npm version or running a locked local install. Treat results as a screening aid rather than a final compliance decision, and be aware that the tool caches downloaded sanctions data in a predictable temp file and depends on unauthenticated CSV download integrity.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T08 · Insecure Dependencies

Error
Location
SKILL.md:19
Finding

Unpinned npm Package Is Downloaded and Executed Without Confirmation

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/index.ts:13
Finding

Predictable Shared Temporary Cache Allows Symlink Clobbering and Sanctions-Data Poisoning

Content
View full analysis
{ return new Promise((resolve, reject) => { const file = fs.createWriteStream(dest); https.get(url, (response) => { if (response.statusCode === 301 || response.statusCode === 302) { const redirectUrl = response.headers.location; if (redirectUrl) { file.close(); fs.unlinkSync(dest); downloadFile(redirectUrl, dest).then(resolve, reject); return; } } if (response.statusCode && response.statusCode !== 200) { file.close(); fs.unlink(dest, () => {}); reject(new Error(`HTTP request failed with status code ${response.statusCode}`)); return; } response.pipe(file); file.on("finish", () => { file.close(); resolve(); }); }).on("error", (err) => { fs.unlink(dest, () => {}); reject(err); }); }); } async function getSDNData(): Promise { let needsDownload = true; if (fs.existsSync(CACHE_FILE)) { const stats = fs.statSync(CACHE_FILE); const age = Date.now() - stats.mtimeMs; if (age < CACHE_MAX_AGE_MS) { needsDownload = false; } } if (needsDownload) { await downloadFile(SDN_URL, CACHE_FILE); } const csvContent = fs.readFileSync(CACHE_FILE, "utf-8"); ``` ### Technical Analysis The application uses a constant filename under the operating system's shared temporary directory. It opens that path through `fs.createWriteStream()` without establishing a privat ...[truncated 2038 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/index.ts:12
Finding

Unrestricted Data-Source Override and Redirect Handling Permit Sanctions-Feed Substitution

Content
View full analysis
{ return new Promise((resolve, reject) => { const file = fs.createWriteStream(dest); https.get(url, (response) => { if (response.statusCode === 301 || response.statusCode === 302) { const redirectUrl = response.headers.location; if (redirectUrl) { file.close(); fs.unlinkSync(dest); downloadFile(redirectUrl, dest).then(resolve, reject); return; } } if (response.statusCode && response.statusCode !== 200) { file.close(); fs.unlink(dest, () => {}); reject(new Error(`HTTP request failed with status code ${response.statusCode}`)); return; } response.pipe(file); file.on("finish", () => { file.close(); resolve(); }); }).on("error", (err) => { fs.unlink(dest, () => {}); reject(err); }); }); } ``` ### Technical Analysis The source URL can be replaced through the undocumented `SDN_URL` environment variable. The implementation does not restrict the hostname to an official Treasury domain or otherwise authenticate the contents beyond the HTTPS transport connection. HTTP 301 and 302 responses are recursively followed without: - A destination hostname allowlist - A same-origin restriction - A maximum redirect count - A response timeout - A maximum response size - Validation that the ...[truncated 1877 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description promises a concrete compliance-screening capability with specific data access and matching behavior. However, the provided code chunk is just an empty declaration file and does not implement any of those functions. This is a material mismatch because the actual supplied code does not support the stated primary purpose at all.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding

The skill executes an external package via npx -y @vbotholemu/mcp-sanctions-check without pinning an exact version. This creates a supply-chain risk: future package updates or a compromised publisher account could cause different code to run than what was reviewed, potentially leading to arbitrary code execution or data exfiltration.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill solicits sanctions screening of names for compliance use but does not clearly disclose that submitted names are sent to an external MCP service and that OFAC data is downloaded and cached locally. In compliance and KYC contexts, names and related identifiers can be sensitive personal or business data, so hidden transmission and local retention increase privacy, confidentiality, and data-handling risk.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill claims to check names against the official OFAC SDN list, but SDN_URL can be overridden by an environment variable, allowing the tool to silently use an arbitrary remote CSV instead of the authoritative source. In a compliance-screening context, this can cause false negatives or manipulated results that let sanctioned parties pass screening, which is a security and regulatory integrity issue even if no code execution occurs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

This code automatically downloads the OFAC SDN CSV over HTTPS and writes it to a temporary local cache file, but there is no user-facing prompt, log message, comment, or other disclosure around that behavior. Because this is a code file, outbound network access and file writes should have some visible warning unless clearly disclosed elsewhere in the skill description, which is not present in this file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code automatically downloads the OFAC SDN dataset over HTTPS and writes it to a temporary local cache file before processing it. There is no confirmation prompt, user-facing log, or inline disclosure near this behavior, so users may not realize the tool performs network access and local file writes when invoked.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 25)May include surrounding context.

json
"author": "velocibot",
  "license": "MIT",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.12.1",
    "csv-parse": "^5.6.0",
    "zod": "^3.23.0"
  },

Unverifiable Dependency: @modelcontextprotocol/sdk has 3 known advisory(ies) (CVE-2026-25536 (@modelcontextprotocol/sdk has cross-client data leak via shared server/transport); CVE-2026-0621 (Anthropic's MCP TypeScript SDK has a ReDoS vulnerability); CVE-2025-66414 (Model Context Protocol (MCP) TypeScript SDK does not enable DNS rebinding protec)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
84% confidence
Finding

The manifest allows a floating @modelcontextprotocol/sdk version while known advisories exist for some releases, so consumers may install an affected version without realizing it. In an MCP skill that processes compliance queries and likely exposes network-facing tool behavior, SDK flaws such as data leakage, ReDoS, or missing DNS rebinding protections can meaningfully expand attack surface.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 26)May include surrounding context.

json
"license": "MIT",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.12.1",
    "csv-parse": "^5.6.0",
    "zod": "^3.23.0"
  },
  "devDependencies": {

Unverifiable Dependency: csv-parse has 2 known advisory(ies) (CVE-2019-17592 (Regular Expression Denial of Service in csv-parse); CVE-2026-85063 (node-csv: Prototype replacement still reachable via columns path)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
78% confidence
Finding

csv-parse has known advisories in some versions, and the unpinned manifest makes it impossible to verify whether installations will avoid affected releases. Because this skill downloads and parses external OFAC CSV data, parser-level DoS or unsafe object-handling bugs could be triggered through maliciously crafted or tampered input if transport or source integrity is compromised.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 27)May include surrounding context.

json
"dependencies": {
    "@modelcontextprotocol/sdk": "^1.12.1",
    "csv-parse": "^5.6.0",
    "zod": "^3.23.0"
  },
  "devDependencies": {
    "typescript": "^5.7.0",

Unverifiable Dependency: zod has 1 known advisory(ies) (CVE-2023-4316 (Zod denial of service vulnerability)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
74% confidence
Finding

The zod dependency is not pinned despite a known advisory affecting some versions, so the installed package may be vulnerable depending on resolution time. If the skill validates untrusted MCP inputs with an affected release, crafted payloads could cause denial-of-service through expensive validation paths.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 30)May include surrounding context.

json
"zod": "^3.23.0"
  },
  "devDependencies": {
    "typescript": "^5.7.0",
    "@types/node": "^22.0.0"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 31)May include surrounding context.

json
},
  "devDependencies": {
    "typescript": "^5.7.0",
    "@types/node": "^22.0.0"
  }
}