Back to skill

Security audit

V Identity Ilhant34

Security checks for vulnerabilities and agentic risk

Overview

This identity skill is mostly purpose-aligned, but it should be reviewed carefully because it can store high-value private identity keys locally in plaintext by default.

Install only if you are comfortable creating a persistent agent DID and storing its private keys on this machine. Set BILLIONS_NETWORK_MASTER_KMS_KEY before creating or importing an identity, run it in an isolated account or environment, protect $HOME/.openclaw/billions, and treat old signed challenge tokens as reusable unless the implementation is changed to expire and consume them.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/shared/storage/keys.js:47
Finding
Private identity keys are stored unencrypted by default<![CDATA[ ## Vulnerability Details **File Location**: `scripts/shared/storage/keys.js:47-58`; `scripts/shared/storage/base.js:27-31` **Vulnerability Type**: Plaintext storage of cryptographic private keys **Risk Level**: High ### Vulnerable Code ```js _encodeEntry({ alias, privateKeyHex, createdAt }) { const masterKey = getMasterKey(); if (masterKey) { return { version: 1, provider: "encrypted", data: { alias, key: encryptKey(privateKeyHex, masterKey), createdAt }, }; } return { version: 1, provider: "plain", data: { alias, key: privateKeyHex, createdAt }, }; } ``` The resulting key data is written without an explicitly restrictive file mode: ```js async writeFile(data) { await this.ensureDirectory(); const json = JSON.stringify(data, null, 2); const tempPath = `${this.filePath}.tmp`; await fs.writeFile(tempPath, json, "utf-8"); await fs.rename(tempPath, this.filePath); } ``` ### Technical Analysis The key-storage implementation only encrypts private keys when `BILLIONS_NETWORK_MASTER_KMS_KEY` is configured. The environment variable is documented as optional, so the default execution path stores each private key directly as a hexadecimal string in `$HOME/.openclaw/billions/kms.json`. The storage layer also creates the temporary key file without an explicit `mode` option and creates the containing directory without explicitly requiring mode `0700`. Actual permissions therefore depend on the process umask and existing directory permissions. A permissive environment can make the sensitive file accessible to other local users or processes. AES-256-GCM is used when a master key is configured, but that protection does not mitigate the default plaintext path. ### Attack Path 1. A user creates or imports an identity without setting `BILLIONS_NETWORK_MASTER_KMS_KEY`. 2. `KeysFileStorage._encodeEntry()` selects the `provider: "plain"` branch. 3. The private key is serialized into `$HOME/.openclaw/billion ...[truncated 944 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make encrypted key storage mandatory for identity creation and import. Refuse to persist new keys when no secure master-key source is available. 2. Prefer an operating-system keychain, hardware-backed keystore, or dedicated secrets manager instead of storing the encryption key in the same filesystem context. 3. Create `$HOME/.openclaw/billions` with mode `0700`. 4. Create both temporary and final sensitive files with mode `0600`, and verify existing permissions before use. 5. Use exclusive file creation where appropriate and retain atomic replacement behavior. 6. Detect legacy and `provider: "plain"` entries and migrate them to encrypted storage after explicit user confirmation. 7. Warn users clearly if plaintext legacy data is detected, and prevent silent downgrade from encrypted to plaintext storage. 8. Document secure rotation and recovery procedures for the master key. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/verifySignature.js:19
Finding
Authentication challenges can be replayed indefinitely<![CDATA[ ## Vulnerability Details **File Location**: `scripts/shared/storage/challenge.js:8-29`; `scripts/verifySignature.js:19-55` **Vulnerability Type**: Missing challenge expiration and single-use enforcement **Risk Level**: Medium ### Vulnerable Code The challenge timestamp is recorded but no expiration policy is implemented: ```js async save(did, challenge) { const entries = await this.readFile(); const created_at = new Date(); const index = entries.findIndex((entry) => entry.did === did); if (index >= 0) { // Update existing entry entries[index] = { did, challenge, created_at }; } else { // Add new entry entries.push({ did, challenge, created_at }); } await this.writeFile(entries); } async find(did) { const entries = await this.readFile(); return entries.find((entry) => entry.did === did); } async getChallenge(did) { const entry = await this.find(did); return entry?.challenge; } ``` Verification compares the signed value with the stored challenge but neither checks its age nor consumes it after success: ```js // Get the stored challenge const challenge = await challengeStorage.getChallenge(args.did); if (!challenge) { console.error(`Error: No challenge found for DID: ${args.did}`); console.error("Generate a challenge first with generateChallenge.js"); process.exit(1); } // Create DID resolver that fetches from remote resolver const resolveDIDDocument = { resolve: async (did) => { const resp = await fetch( `https://resolver.privado.id/1.0/identifiers/${did}`, ); const didResolutionRes = await resp.json(); return didResolutionRes; }, }; // Create JWS packer and unpack token const jws = new JWSPacker(kms, resolveDIDDocument); const basicMessage = await jws.unpack(byteEncoder.encode(args.token)); // Verify the sender if (basicMessage.from !== args.did) { console.error( `Error: Invalid from: expected from ${args.did}, got ${basicMessage.from}`, ); process.exit(1); } ...[truncated 2320 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce a short challenge lifetime by retrieving and validating `created_at` during verification. 2. Atomically consume or delete the challenge immediately after successful verification. 3. Prevent race-condition replays by combining comparison and consumption into one atomic storage operation or protected transaction. 4. Bind each challenge to a unique verification session, intended audience, operation, and requester. 5. Include a unique nonce or token identifier and maintain a consumed-token registry for the relevant retention period. 6. Reject missing, malformed, future-dated, expired, or already-consumed challenge records. 7. Avoid placing signed tokens in logs or persistent command histories, and redact them from diagnostic output. 8. Add tests covering expiration, repeated submission, concurrent verification, challenge replacement, and session/audience mismatch. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (38)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The stated purpose focuses on identity verification and attestation, but the skill also performs local private-key storage, persistence, and key-management operations. That mismatch can mislead users and agent frameworks into approving a skill with far more sensitive authority than its description suggests, enabling unexpected credential handling and long-term secret retention.

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [agent_skills]

High
Category
YARA Match
Content
nk agents to human identities using Billions ERC-8004 and Attestation Registries. Verify and generate authentication proofs. Based on iden3 self-sovereign identity protocol.
metadata: { "category": "identity", "clawdbot": { "requires": { "bins": ["node"] }, "config": { "optionalEnv": ["BILLIONS_NETWORK_MASTER_KMS_KEY"] } } }
homepage: https://billions.network/
---

## When to use this Skill

Lets AI agents create and manage their own identities on the Billions Network, and link those identities to a human owner.

1. When you need to link your agent identity to an owner.
2. When you need to sign a challenge.
3. When you need to link a human to the agent's DID.
4. When you need to verify a signature to confirm identity ownership.
5. When you use shared JWT tokens for authentication.
6. When you need to create and manage decentralized identities.

### After installing the plugin run the following commands to create an identity and link it to your human DID:

```bash
cd scripts && npm inst
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Credential Access

High
Category
Privilege Escalation
Content
- `kms.json` - **CRITICAL**: Contains private keys (encrypted if BILLIONS_NETWORK_MASTER_KMS_KEY is set, otherwise in plaintext)
- `defaultDid.json` - DID identifiers and public keys
- `challenges.json` - Authentication challenges history
- `credentials.json` - Verifiable credentials
- `identities.json` - Identity metadata
- `profiles.json` - Profile data
Confidence
93% confidence
Finding
The skill explicitly handles sensitive credential material, including private keys and verifiable credentials stored on disk. In context, identity tooling must process credentials, but storing them locally—especially with optional plaintext key storage—creates a high-value target for theft, misuse, or lateral access by other tools/processes.

Known Vulnerable Dependency: ws==8.18.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
97% confidence
Finding
The lockfile includes ws 8.18.0, which is flagged for memory disclosure and memory-exhaustion denial of service issues. In an identity/authentication skill that may handle websocket-based RPC or provider traffic, remotely triggerable DoS or memory exposure in a networking library is a meaningful supply-chain risk.

Known Vulnerable Dependency: brace-expansion==2.1.0 — 3 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro); CVE-2026-69152 (brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-1)

High
Category
Supply Chain
Confidence
95% confidence
Finding
brace-expansion 2.1.0 is flagged for multiple denial-of-service conditions caused by pathological expansion behavior and memory growth. Although often used in tooling or parsing paths, any reachable processing of attacker-controlled patterns can lead to CPU or memory exhaustion.

Known Vulnerable Dependency: fast-uri==3.1.0 — 7 advisory(ies): CVE-2026-13676 (fast-uri vulnerable to host confusion via failed IDN canonicalization); CVE-2026-18446 (fast-uri vulnerable to host confusion via backslash authority introducer); CVE-2026-75975 (fast-uri vulnerable to server-side request forgery via malformed IPv6 normalizat) +4 more

High
Category
Supply Chain
Confidence
96% confidence
Finding
fast-uri 3.1.0 is reported for several URI parsing and canonicalization issues including host confusion and SSRF-related edge cases. Because this skill interacts with decentralized identity documents, registries, and remote resources, malformed URI handling could make trust or fetch decisions against the wrong host.

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
96% confidence
Finding
ws 7.5.10 is reported vulnerable to memory exhaustion from tiny fragments and data chunks, enabling denial of service via malicious websocket traffic. Since the dependency tree includes RPC and provider components, websocket exposure is plausible and makes this more relevant than a purely build-time issue.

Known Vulnerable Dependency: underscore==1.13.6 — 1 advisory(ies): CVE-2026-27601 (Underscore has unlimited recursion in _.flatten and _.isEqual, potential for DoS)

High
Category
Supply Chain
Confidence
93% confidence
Finding
underscore 1.13.6 is flagged for unlimited recursion in functions like _.flatten and _.isEqual, which can crash or hang a process on crafted deeply nested input. In services processing external credential, DID, or RPC data, this can become a reachable availability issue if these helpers are invoked on attacker-controlled structures.

Known Vulnerable Dependency: undici==5.29.0 — 12 advisory(ies): CVE-2026-1525 (Undici has an HTTP Request/Response Smuggling issue); CVE-2026-6733 (undici vulnerable to HTTP response queue poisoning via keep-alive socket reuse); CVE-2026-1527 (Undici has CRLF Injection in undici via `upgrade` option) +9 more

High
Category
Supply Chain
Confidence
98% confidence
Finding
undici 5.29.0 is associated with numerous HTTP parsing and request/response handling issues, including smuggling, queue poisoning, and CRLF-related flaws. This is especially concerning for an identity skill that likely fetches remote documents or communicates with registries and verifiers, where outbound HTTP trust boundaries matter.

Known Vulnerable Dependency: ws==8.17.1 — 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
97% confidence
Finding
ws 8.17.1 is another vulnerable websocket library instance affected by memory disclosure and memory exhaustion DoS issues. Multiple vulnerable websocket copies in the dependency tree broaden the attack surface and increase the chance that at least one reachable code path remains exploitable.

Known Vulnerable Dependency: ws==8.18.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
94% confidence
Finding
The lockfile includes ws 8.18.0, which is flagged for uninitialized memory disclosure and memory-exhaustion denial of service. This is especially relevant because the skill depends on networking-heavy identity, blockchain, and websocket-capable libraries; if the skill opens websocket connections to untrusted peers or relays, an attacker may be able to crash the process or potentially expose process memory.

Credential Access

High
Category
Privilege Escalation
Content
function newDataStorage(ethStateStorage) {
  return {
    credential: new CredentialStorage(
      new IdentitiesFileStorage("credentials.json"),
    ),
    identity: new IdentityStorage(
      new IdentitiesFileStorage("identities.json"),
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
function newDataStorage(ethStateStorage) {
  return {
    credential: new CredentialStorage(
      new IdentitiesFileStorage("credentials.json"),
    ),
    identity: new IdentityStorage(
      new IdentitiesFileStorage("identities.json"),
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

High
Confidence
99% confidence
Finding
The code silently falls back to writing plaintext private keys to `kms.json` without any warning, consent, or hard failure when key encryption is not configured. This creates a high-risk secret exposure path that operators may not realize exists, especially dangerous here because the keys back identity verification and authentication proofs.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The README instructs users to run `npx clawhub@latest install verified-agent-identity`, which pulls and executes the latest published package version at install time. This creates a supply-chain risk because a compromised or malicious future release of `clawhub` could execute arbitrary code on the host during installation.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
This installation command again relies on `npx clawhub@latest`, causing users to execute whatever code is published in the newest package version. In an identity-management skill that handles keys and credentials, this is especially sensitive because installer compromise could steal secrets or backdoor the environment before the skill is even used.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill declares executable behavior that can use environment variables and communicate with external registries, but it does not declare an explicit tool/permission scope. In an agent setting, this weakens operator visibility and policy enforcement, increasing the chance the skill is invoked with broader capabilities than users expect.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The setup instructions tell users to create an identity before prominently warning that private keys may be stored locally in plaintext when no master KMS key is configured. This can cause accidental insecure key creation, especially in automated agent environments where users may never review later security notes.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The linking workflow encourages challenge signing and identity linking without an upfront notice that DIDs, challenges, credentials, and related artifacts are persisted under the user's home directory. In a shared or managed agent runtime, that persistence can expose sensitive identity metadata or leave durable authentication artifacts behind.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
When no master key is configured, `_encodeEntry` stores `privateKeyHex` directly on disk in plaintext. For an identity/authentication skill, exposure of private keys enables full impersonation, proof forgery, and persistent compromise of agent identity, so the skill context makes this more dangerous rather than less.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The `list()` method returns full private key material for every stored entry, unnecessarily broadening access to the most sensitive secret in the system. In a decentralized identity skill, listing private keys directly increases the blast radius of any misuse, logging leak, or downstream caller compromise because it exposes all agent identities at once.

Known Vulnerable Dependency: uuid==13.0.0 — 1 advisory(ies): CVE-2026-41907 (uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided)

Low
Category
Supply Chain
Confidence
84% confidence
Finding
uuid 13.0.0 is present and is reported vulnerable when v3/v5/v6 APIs are called with a caller-provided buffer lacking proper bounds checks. This is lower severity and may not be reachable in normal use, but it is still a real dependency risk if any code path passes attacker-influenced buffer arguments.

Known Vulnerable Dependency: uuid==9.0.1 — 1 advisory(ies): CVE-2026-41907 (uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided)

Low
Category
Supply Chain
Confidence
84% confidence
Finding
uuid 9.0.1 is also present and carries the same bounds-check weakness for certain namespace UUID generation APIs when buf is supplied. Multiple vulnerable versions in the tree increase maintenance risk even if exploitation requires a specific call pattern.

Known Vulnerable Dependency: ajv==8.17.1 — 1 advisory(ies): CVE-2025-69873 (ajv has ReDoS when using `$data` option)

Low
Category
Supply Chain
Confidence
88% confidence
Finding
ajv 8.17.1 is reported vulnerable to ReDoS when the $data option is enabled, which can let crafted inputs consume excessive CPU during schema validation. In an identity-verification stack that may validate externally supplied claims or credential payloads, this can become a practical availability issue if that option is used.

Known Vulnerable Dependency: elliptic==6.6.1 — 1 advisory(ies): CVE-2025-14505 (Elliptic Uses a Cryptographic Primitive with a Risky Implementation)

Low
Category
Supply Chain
Confidence
79% confidence
Finding
elliptic 6.6.1 is identified as using a risky cryptographic implementation, which is concerning in a package set centered on authentication, keys, and proofs. Even when no active exploit is evident from the lockfile alone, weak crypto dependencies in identity-related code deserve treatment as real risk.

Static analysis

No suspicious patterns detected.