Back to skill

Security audit

Clawlet

Security checks for vulnerabilities and agentic risk

Overview

This Nostr skill is mostly purpose-aligned, but it needs review because it stores and exports account-controlling private keys in plaintext and falls back to a shared default identity when user context is missing.

Review carefully before installing. Use only throwaway or low-value Nostr identities unless the skill is updated to encrypt keys or use a keychain, require authenticated user context, add confirmations for key export and network-visible actions, verify relay events, and refresh the dependency lockfile. Treat anything posted or followed through this skill as relay-distributed public activity, and treat DMs as encrypted content with observable metadata.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
index.js:42
Finding

Plaintext Storage of Nostr Private Keys with Unrestricted Default Permissions

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
index.js:542
Finding

Missing Authentication Context Falls Back to a Shared Privileged Identity

Content
View full analysis
{ const userId = context?.user?.id || 'default'; const identity = getIdentity(userId); if (!identity) { return { success: false, message: '你还没有 Nostr 身份' }; } return { success: true, privateKey: identity.privateKey, npub: identity.npub, warning: '请妥善保管私钥,不要泄露给他人' }; }, ``` Equivalent fallback logic is used by identity creation and retrieval, posting, timeline access, interest management, direct messaging, and nickname management: ```js const userId = context?.user?.id || 'default'; ``` ### Technical Analysis User isolation depends entirely on `context.user.id`, but the implementation does not require that authenticated identity information be present. If the context or user ID is absent, every caller is mapped to the literal identifier `default`. This converts an authentication failure into access to a shared account. Because the shared identity can be created, exported, used to publish signed events, and used to decrypt direct messages, the fallback crosses a security boundary rather than merely selecting harmless default configuration. The export function compounds the problem by returning the raw private key without re-authentication, explicit authorization checks, or confirmation of a trusted output channel. ### Attack Path 1. A legitimate or contextless caller creates a Nostr identity while `context.user.id` is unavailable, causing it to be stored under `default`. 2. A second caller invokes a Skill function without a populated authenticated context. 3. The second caller is also resolved to the `default` ide ...[truncated 843 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:253
Finding

Unverified Events from Nostr Relays Are Treated as Trusted Data

Content
View full analysis
{ try { const msg = JSON.parse(data.toString()); if (msg[0] === 'EVENT' && msg[1] === subId) { events.push(msg[2]); } else if (msg[0] === 'EOSE' && msg[1] === subId) { if (!resolved) { resolved = true; completed++; ws.close(); } } } catch (e) {} }); ``` The returned event is subsequently consumed without calling `verifyEvent`. For example, profile data is parsed directly: ```js const profile = JSON.parse(events[0].content); ``` Direct-message events are also processed using attacker-supplied event fields: ```js for (const event of events) { try { // 获取发件人公钥 const senderPubkey = event.pubkey; // 解密内容 const decryptedContent = nip04Decrypt(sk, senderPubkey, event.content); dms.push({ id: event.id, from: senderPubkey, fromNpub: npubEncode(senderPubkey), content: decryptedContent, created_at: new Date(event.created_at * 1000).toISOString() }); } catch (e) { // 解密失败,跳过 console.log('解密失败:', e.message); } } ``` ### Technical Analysis Nostr event integrity is based on the event ID and digital signature. A relay is a transport and storage service, not a trusted signer. The Skill verifies events that it creates locally but does not call `verifyEvent` on events received from relays. As a result, a malicious or compromised relay can return an event containing an arbitrary `pubkey`, `content`, timestamp, ID, kind, or tag set. The Skill then displays, scores, parses, or attempts to decrypt those fi ...[truncated 1556 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
package-lock.json:19
Finding

Cryptographic Dependency Tree Is Locked to a Third-Party npm Registry Mirror

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill description presents normal Nostr assistant features, but the file also indicates that users can export private keys and that private keys are stored locally in data/identities.json. Handling and exporting long-term private keys is highly sensitive; if users are not clearly warned up front, they may invoke the skill without understanding that account-compromising secret material will be stored and can be revealed.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Private keys are stored in a local JSON file in plaintext, which is a sensitive-secret storage weakness. Any local compromise, backup leakage, container escape, shared-host access, or accidental file exposure would immediately disclose all user identities and enable account takeover and DM decryption.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill exposes a direct private-key export capability even though the described skill purpose does not clearly establish key backup/export as a required operation. In this context, the private key is the user's full Nostr identity; any caller able to invoke this action can permanently impersonate the user, decrypt future/archived DMs available to that key, and take over the account.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

Although the DM content is encrypted, sending private messages to third-party relays still exposes metadata such as sender, recipient, timing, and event IDs, and places sensitive communication onto external infrastructure. Without explicit warning/consent in the action path, users may wrongly assume stronger privacy guarantees than Nostr relays actually provide.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ws==8.19.0 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
98% confidence
Finding

The lockfile pins ws to 8.19.0, and the supplied finding identifies known advisories for that exact version involving memory disclosure and memory-exhaustion denial of service. In this skill, WebSocket handling is central to Nostr relay communication, so an exposed vulnerable ws client/library increases risk because the skill processes untrusted network traffic from external relays.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ws==8.19.0 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
98% confidence
Finding

The skill depends on ws 8.19.0, which is flagged with advisories for uninitialized memory disclosure and memory-exhaustion denial of service. In the context of a Nostr client/agent that communicates over WebSockets and processes untrusted remote data, these issues are more dangerous because an attacker-controlled relay or peer could potentially trigger information leakage or exhaust process memory.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README advertises generation and management of Nostr keys but provides no warning that these are highly sensitive credentials whose disclosure would allow account takeover and impersonation. In an agent skill context, users may ask the assistant to create or handle keys conversationally, increasing the chance that private keys are exposed in logs, chat history, screenshots, or insecure storage.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The README describes sending content to the Nostr network without warning that posts may be public, replicated across relays, and difficult or impossible to retract. In this skill's context, users may treat the agent like a private assistant and unknowingly instruct it to publish sensitive, personal, or regulated information to a public network.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
79% confidence
Finding

The skill performs sensitive operations around Nostr identity management and private-key handling, yet the manifest does not declare an explicit tool scope or permissions boundary. Missing scope makes it harder for users and the host to understand what resources the skill may access, increasing the risk of overbroad execution or unintended access to environment-backed secrets.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill advertises posting and private messaging features but does not clearly warn in the main description that content will be transmitted to external relays. In this context, omission is more dangerous because Nostr posts and relay-delivered messages can be widely replicated or metadata-exposed, and users may not realize they are sending data off-device to third-party infrastructure.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger examples include broad everyday phrases like '有什么新消息', which can overlap with ordinary conversation and unintentionally activate the skill. Because this skill can post content, manage identities, and send direct messages, accidental invocation could lead to unintended external actions or disclosure of social-graph and message data.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

User-facing strings throughout the skill are consistently in Chinese, and the header brands the tool in Chinese, but there is no opt-in language selection or explanation that the skill is intended only for a Chinese-language audience. This can violate a language/locale policy requiring user choice or explicit locale justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This function publishes user-provided content to multiple external WebSocket relays, which is a network transmission of user data. The code does not show a confirmation prompt, visible log/print, or warning in this path that the content will be sent to third-party relays.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

Following a user creates and publishes a social graph event to external relays. There is no prompt, visible logging, or explanatory warning in this action path informing the user that the follow event will be broadcast publicly to third-party servers.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest says the skill can read a timeline, which normally implies the user's Nostr timeline or feed. The implementation fetches recent kind-1 events from relays without using the user's follow list, so it behaves like a global public feed reader rather than a user-specific timeline.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The relay fetch helper opens WebSocket connections to external Nostr relays and sends query filters, which is network activity involving user-driven lookups. There is no visible prompt, log, or explanatory comment indicating to the user that external relay access occurs for reads as well as writes.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The inline documentation describes '发送私信并等待回复(模拟对话)', implying conversational reply handling. In reality, the function just delegates to the send operation and returns immediately with a note to use another function to view replies, which contradicts the stated intent of waiting for a response.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
88% confidence
Finding

The dependency uses a caret range, which permits automatic installation of newer minor/patch releases instead of a fully fixed version. This weakens supply-chain reproducibility and can unexpectedly introduce vulnerable or malicious upstream changes, though by itself it is a lower-severity hygiene issue.

Content

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

json
"author": "",
  "license": "ISC",
  "dependencies": {
    "https-proxy-agent": "^7.0.6",
    "nostr-tools": "^2.23.1",
    "ws": "^8.19.0"
  }

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
88% confidence
Finding

The nostr-tools dependency is specified with a caret range, allowing non-identical builds over time as upstream minor/patch releases are pulled in. For a skill that manages identities, timelines, and private messaging, this increases supply-chain risk because cryptographic or protocol-handling behavior could change without review.

Content

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

json
"license": "ISC",
  "dependencies": {
    "https-proxy-agent": "^7.0.6",
    "nostr-tools": "^2.23.1",
    "ws": "^8.19.0"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

The ws package is not only unpinned via a caret range but is also the WebSocket library likely exposed to untrusted network traffic in this Nostr skill. Unpinned network-facing dependencies raise supply-chain risk and make it easier for insecure or unexpected upstream changes to reach production unnoticed.

Content

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

json
"dependencies": {
    "https-proxy-agent": "^7.0.6",
    "nostr-tools": "^2.23.1",
    "ws": "^8.19.0"
  }
}

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest description is written entirely in Chinese and presents the skill as a general-purpose "smart assistant" for Nostr, with no indication that the skill is China-specific or that users can choose another language. This can conflict with language/locale policy expectations when a skill is not explicitly scoped to a Chinese-speaking audience.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.