Back to skill

Security audit

dchat

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches its messaging purpose, but its default media receiving path can let remote senders write outside the media cache or exhaust local resources.

Review before installing. Use only in an isolated user account or sandbox until the media path traversal, incoming size limits, sender-selected gateway behavior, dependency updates, and missing packaged wrapper/dist files are fixed. Treat received media as untrusted, disable or gate automatic downloads, and understand that the skill creates a persistent local NKN identity, message database, and media cache while connecting to NKN and IPFS networks.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
src/media.ts:139
Finding

Remote Path Traversal Allows Arbitrary File Writes Outside the Media Cache

Content
View full analysis
{ const ext = fileExt.startsWith(".") ? fileExt : `.${fileExt}`; const cachedPath = path.join(this.cacheDir, `${ipfsHash}${ext}`); if (fs.existsSync(cachedPath)) return cachedPath; const encryptedData = await this.ipfs.download(ipfsHash, preferredIp); const key = Buffer.from(keyBytes); const decrypted = decrypt(encryptedData, key, nonceSize); fs.writeFileSync(cachedPath, decrypted); return cachedPath; } ``` ```ts // src/media.ts:160-169 saveInlineAudio(messageId: string, content: string, fileExt = "aac"): string { const ext = fileExt.startsWith(".") ? fileExt : `.${fileExt}`; const localPath = path.join(this.cacheDir, `${messageId}${ext}`); const match = content.match(/^!\[audio\]\(data:[^;]+;base64,(.+)\)$/s); const rawBase64 = match ? match[1] : content; fs.writeFileSync(localPath, Buffer.from(rawBase64, "base64")); return localPath; } ``` ### Technical Analysis The receive path treats `messageId`, `options.ipfsHash`, and `options.fileExt` as trusted path components. These values originate in an incoming NKN message and are not constrained by a runtime schem ...[truncated 2765 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/ipfs.ts:153
Finding

Unbounded Incoming Media Processing Enables Memory and Disk Exhaustion

Content
View full analysis
{ const headers: Record = {}; if (gw.authHeader) headers["Authorization"] = gw.authHeader; return new Promise((resolve, reject) => { const client = gw.protocol === "https:" ? https : http; const req = client.request( { hostname: gw.host, port: gw.port, path: `/api/v0/cat?arg=${encodeURIComponent(ipfsHash)}`, method: "POST", headers, }, (res) => { if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) { res.resume(); reject(new Error(`IPFS download failed (${res.statusCode}) for ${ipfsHash}`)); return; } const chunks: Buffer[] = []; res.on("data", (chunk: Buffer) => chunks.push(chunk)); res.on("end", () => resolve(Buffer.concat(chunks))); }, ); req.on("error", reject); req.setTimeout(60000, () => req.destroy(new Error("IPFS download timeout"))); req.end(); }); } ``` ```ts // src/media.ts:160-169 saveInlineAudio(messageId: string, content: string, fileExt = "aac"): string { const ext = fileExt.startsWith(".") ? fileExt : `.${fileExt}`; const localPath = path.join(this.cacheDir, `${messageId}${ext}`); const match = content.match(/^!\[audio\]\(data:[^;]+;base64,(.+)\)$/s); const rawBase64 = match ? match[1] : content; fs.writeFileSync(localPath, Buffer.from(rawBase64, "base64")); return localPath; } ``` ```ts // src/bot.ts:311-322 if (this.config.autoDownloadMedia && msgData.options) { try { const localPath = await this.downloadMediaFromOptions( msgData.id, msgData.contentType, msgData.content ...[truncated 2925 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/ipfs.ts:82
Finding

DNS Rebinding Weakens SSRF Protection for Sender-Selected IPFS Gateways

Content
View full analysis
{ // If it's already an IP literal, check directly if (isIP(host)) { return !this.isPrivateOrReservedIp(host); } // Resolve DNS and check ALL resolved addresses try { const addresses = await dns.resolve(host); if (addresses.length === 0) return false; return addresses.every((addr) => !this.isPrivateOrReservedIp(addr)); } catch { return false; // DNS resolution failed — reject } } ``` ```ts // src/ipfs.ts:98-110 private async orderGateways(preferredIp?: string): Promise { if (!preferredIp) return this.gateways; const preferred = this.gateways.filter((g) => g.host === preferredIp); const rest = this.gateways.filter((g) => g.host !== preferredIp); if (preferred.length === 0) { // Ad-hoc gateway from message options — resolve DNS and verify public const isPublic = await this.isPublicHost(preferredIp); if (!isPublic) { console.warn(`[IpfsService] Rejected non-public gateway: ${preferredIp}`); return this.gateways; } return [{ host: preferredIp, port: 80, protocol: "http:" }, ...this.gateways]; } return [...preferred, ...rest]; } ``` ```ts // src/ipfs.ts:161-169 const req = client.request( { hostname: gw.host, port: gw.port, path: `/api/v0/cat?arg=${encodeURIComponent(ipfsHash)}`, method: "POST", headers, }, ``` ### Technical Analysis Incoming message metadata can specify `options.ipfsIp`, which is passed to `IpfsService.download()` as the preferred gateway. Unknown gateway names are accepted after `isPublicHost()` resolves and evaluates them. The security check and network connection perform separate DNS operations: ...[truncated 2873 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (45)

Known Vulnerable Dependency: vitest==2.1.9 — 2 advisory(ies): CVE-2026-47429 (When Vitest UI server is listening, arbitrary file can be read and executed); CVE-2026-84373 (Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock)

Critical
Category
Supply Chain
Confidence
90% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: vitest==2.1.9 — 2 advisory(ies): CVE-2026-47429 (When Vitest UI server is listening, arbitrary file can be read and executed); CVE-2026-84373 (Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock)

Critical
Category
Supply Chain
Confidence
97% confidence
Finding

The resolved vitest==2.1.9 version is associated with arbitrary file read and potential code execution issues in the Vitest UI/mocking components. Because this is a devDependency, the production skill is less directly exposed, but developer workstations and CI environments may be at risk if tests or the UI server are run on untrusted projects or networks.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code does not implement NKN messaging, bot-to-bot communication, text/image/audio message handling, encryption, or serverless peer-to-peer transport. Instead, it provides file upload/download functionality against IPFS gateways via HTTP(S), with fallback gateway selection and SSRF-style hostname safety checks. That is a materially different capability and architecture from the declared purpose of private decentralized messaging over NKN.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description is about decentralized bot-to-bot messaging over NKN, including sending and receiving messages and files. The provided code chunk does not implement messaging, networking, media transfer, or NKN communication. Instead, it provides a local secure storage utility for persisting a bot identity on disk with encryption. While secure identity storage could be a supporting component of a messaging system, this chunk's actual behavior is materially different from the declared primary purpose and introduces undeclared filesystem-based credential storage capabilities. Therefore, this code chunk does not accurately represent the declared description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description focuses on decentralized bot-to-bot messaging over NKN, including sending and receiving messages and media. The supplied code does not implement or test messaging, networking, NKN integration, or media transfer. Instead, it tests secure local storage of identity data on disk, including encryption at rest, deletion, overwrite behavior, and restrictive file permissions. While secure identity storage could support a messaging system, this chunk’s actual behavior is materially different from the declared primary purpose and involves undeclared filesystem capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

There is a clear mismatch between the declared description and the supplied code. The description claims a decentralized encrypted messaging capability over NKN, but the code chunk is only a test runner configuration file for Vitest. This is unrelated to the declared core behavior and does not demonstrate any messaging, networking, media handling, or security functionality.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: axios==1.13.6 — 16 advisory(ies): CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more

High
Category
Supply Chain
Confidence
92% confidence
Finding

axios is a runtime dependency pulled in by nkn-sdk, and the listed advisories include SSRF/proxy bypass and prototype-pollution-related MITM or credential exposure scenarios. In a decentralized messaging skill that communicates over networks and may handle untrusted endpoints or redirects, a vulnerable HTTP client can meaningfully expand attack surface.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
88% confidence
Finding

form-data is a direct dependency and a CRLF injection flaw in multipart field names or filenames can enable request smuggling-like manipulation, header injection, or malformed upstream requests when attacker-controlled file metadata is sent. In a messaging/file-transfer skill, handling untrusted filenames makes this especially relevant.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: nanoid==3.3.11 — 3 advisory(ies): CVE-2026-67214 (nanoid: non-secure generators can loop indefinitely with negative size); CVE-2026-67213 (nanoid: custom generators can loop indefinitely when size is zero); CVE-2026-73086 (nanoid: Integer Overflow or Wraparound)

High
Category
Supply Chain
Confidence
80% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: postcss==8.5.8 — 4 advisory(ies): CVE-2026-45623 (PostCSS: Arbitrary file read and information disclosure via attacker-controlled ); CVE-2026-69153 (PostCSS: incomplete fix of GHSA-6g55-p6wh-862q — attacker-controlled sourceMappi); CVE-2026-41305 (PostCSS has XSS via Unescaped </style> in its CSS Stringify Output) +1 more

High
Category
Supply Chain
Confidence
80% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: vite==5.4.21 — 3 advisory(ies): CVE-2026-39365 (Vite Vulnerable to Path Traversal in Optimized Deps `.map` Handling); CVE-2026-53571 (vite: `server.fs.deny` bypass on Windows alternate paths); CVE-2026-53632 (launch-editor: NTLMv2 hash disclosure via UNC path handling on Windows)

High
Category
Supply Chain
Confidence
80% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ws==7.5.10 — 1 advisory(ies): CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
89% confidence
Finding

ws 7.5.10 is a runtime dependency of nkn-sdk, and a memory exhaustion DoS via tiny fragments/chunks is particularly relevant for a P2P messaging skill that accepts network-originated websocket traffic. An attacker could degrade availability or crash the process by sending pathological frames.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
98% confidence
Finding

form-data==4.0.5 is flagged with a CRLF injection advisory, which can allow crafted multipart field names to manipulate generated HTTP request bodies or headers. In a messaging skill that may send files or media, unsafe multipart construction can become relevant if untrusted metadata is included in outbound requests, increasing the chance of request smuggling or downstream parser abuse.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The README states that installation automatically generates a bot identity and enables decentralized messaging and file transfer, but it does not clearly warn users that this creates persistent cryptographic identity material and may initiate network-visible communications and data handling. In an agent skill context, this omission is risky because operators may install or invoke the skill without understanding privacy, metadata, storage, and network exposure implications.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill explicitly instructs use of shell execution and describes network access, filesystem storage, and environment-dependent behavior, but it declares no tool scope such as allowed-tools or permissions. That creates unnecessary ambient authority: an agent may invoke shell/environment capabilities broader than required, increasing the blast radius if the wrapper or downstream commands are abused.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding

The e2e test script invokes npx tsx, which can fetch and execute a package version that is not explicitly pinned at invocation time. Even though tsx is listed in devDependencies, using npx in automation increases supply-chain risk if the local dependency is absent or resolution behavior changes, leading to unintended code execution during testing.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The bot automatically downloads attacker-controlled media from incoming messages and writes it to disk whenever autoDownloadMedia is enabled, which defaults to true. In a P2P messaging context this can be abused to force unsolicited storage consumption, trigger retrieval of malicious or illegal content, and potentially expose downstream file-handling components to dangerous inputs without any user confirmation.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
83% confidence
Finding

The CLI persists a decryption passphrase to disk in a predictable per-user config location, which means compromise of the same user account or backups can expose both the encrypted identity and the stored key, defeating much of the protection of at-rest encryption. Separating the files into different directories is organizationally helpful but does not provide strong security when both remain accessible to the same principal.

Content

Scanner excerpt · src/cli.ts (reported line 19)May include surrounding context.

ts
// ── Identity helpers ───────────────────────────────────────

/**
 * Get or create a random passphrase for encrypting the identity at rest.
 *
 * The passkey is stored in a SEPARATE directory from the encrypted identity
 * (OS config dir vs data dir) so the encryption key is not alongside the

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The connect method initializes an NKN MultiClient with a user-provided seed and immediately connects to external RPC servers. While there is an internal status update, there is no confirmation prompt, user-facing log/print, or inline warning comment disclosing that the seed is being used for network activity.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
78% confidence
Finding

Both send and sendNoReply transmit caller-provided data over the network, but these methods provide no confirmation, visible user-facing log, or explanatory warning comment about data transmission. For a reusable client skill, this can obscure that arbitrary payloads are being sent to external destinations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The removeContact method performs a DELETE operation on the peer table, which is a destructive change to stored user data. In this file, that action has no confirmation prompt, user-facing log/print, or explanatory warning beyond the method name, so the deletion behavior is not disclosed at the point of execution.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill description emphasizes serverless, private bot-to-bot messaging over NKN without centralized servers. This code adds a separate content transport path via community-operated IPFS gateways over HTTP/HTTPS, which relies on third-party gateway infrastructure and extends behavior beyond direct NKN messaging.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Uploading caller-provided file data to public, community-operated IPFS gateways can disclose sensitive content and metadata to third parties, especially if users assume the skill is only doing private bot-to-bot messaging. In this skill context, the mismatch is more dangerous because the description stresses private, encrypted, serverless communication, which may cause operators or users to trust this path with data they would not knowingly send to external gateway operators.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code allows a caller to influence which external gateway is contacted for downloads via preferredIp, extending network reach beyond the declared skill scope. Although it includes a check intended to block private/reserved IPs, it still enables untrusted input to drive outbound requests to arbitrary public hosts over plain HTTP on port 80, which can expose metadata, weaken integrity/confidentiality, and expand the attack surface for SSRF-like behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.