Back to skill

Security audit

Pairing Agent Core

Security checks for vulnerabilities and agentic risk

Overview

This identity skill is purpose-aligned, but it needs review because it creates and persists long-lived identity private keys with weak default protection and secret-handling patterns.

Install only after reviewing the key-storage tradeoff. Set BILLIONS_NETWORK_MASTER_KMS_KEY before creating any identity, avoid importing an existing wallet/private key with --key, do not pass real tokens or keys in shell commands, and run it under an isolated user/profile. Be aware it stores identity data under $HOME/.openclaw/billions and sends linking/verification traffic to Billions services and resolver.privado.id.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/shared/storage/keys.js:48
Finding
Private Keys Are Stored in Plaintext by Default Without Enforced File Permissions## Vulnerability Details **File Location**: `scripts/shared/storage/keys.js:48-60`; `scripts/shared/storage/base.js:8-9, 27-32` **Vulnerability Type**: Plaintext storage of cryptographic private keys and insufficient filesystem permission enforcement **Risk Level**: High ### Vulnerable Code ```javascript _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 }, }; } ``` ```javascript async ensureDirectory() { const dir = path.dirname(this.filePath); await fs.mkdir(dir, { recursive: true }); } 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 `KeysFileStorage._encodeEntry()` stores private keys directly in `kms.json` whenever `BILLIONS_NETWORK_MASTER_KMS_KEY` is missing, empty, or rejected as too short. Encryption is therefore optional rather than a security requirement. The common storage implementation creates the sensitive directory and files without explicit permission modes. Their permissions consequently depend on the process umask and pre-existing directory permissions. On a permissively configured multi-user host, the resulting key file or its temporary counterpart may be readable by other local users or processes. The temporary file is predictable (`kms.json.tmp`). Although the final rename improves write atomicity, the implementation does not use an exclusive create operation, reject symbolic links, or explicitly secure the temporary file. ### Attack Path ...[truncated 1230 chars]
Remediation
## Remediation Suggestions - Make encrypted storage mandatory for private keys. Fail closed when no master key or protected keystore is available instead of silently selecting plaintext storage. - Prefer an operating-system credential store, hardware-backed key store, or dedicated secrets-management service. - If password-derived encryption is required, derive keys with Argon2id or scrypt using a unique random salt and documented resource parameters. A single SHA-256 operation does not provide password-hardening. - Create `$HOME/.openclaw/billions` with mode `0700` and sensitive files with mode `0600`. - Open temporary files with exclusive creation and no-follow protections, then securely rename them. - Validate the ownership and permissions of existing directories and files before reading or writing keys. - Avoid writing decrypted keys to disk during migration. - Provide a secure migration mechanism that converts existing plaintext entries to encrypted entries and warns users about prior exposure.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generateChallenge.js:16
Finding
Authentication Challenges Can Be Replayed Indefinitely## Vulnerability Details **File Location**: `scripts/generateChallenge.js:16-20`; `scripts/verifySignature.js:47-57`; `scripts/shared/storage/challenge.js:23-29` **Vulnerability Type**: Insufficient challenge entropy, missing expiration, and missing one-time consumption **Risk Level**: Medium ### Vulnerable Code ```javascript // Generate random challenge const challenge = randomInt(0, 10000000000).toString(); // Save challenge to storage await challengeStorage.save(args.did, challenge); ``` ```javascript // Verify the challenge matches const payload = basicMessage.body; if (payload.message !== challenge) { console.error( `Error: Invalid signature: challenge mismatch ${payload.message} !== ${challenge}`, ); process.exit(1); } outputSuccess("Signature verified successfully"); ``` ```javascript async getChallenge(did) { const entry = await this.find(did); return entry?.challenge; } ``` ### Technical Analysis Challenges are selected from only ten billion possible values, providing approximately 33 bits of entropy. This is below the conventional minimum for authentication nonces. The challenge store records a creation time, but `verifySignature.js` does not check it. A stored challenge therefore has no effective expiration. More importantly, successful verification does not call `challengeStorage.delete()` or otherwise mark the challenge as consumed. As a result, a JWS that successfully verifies once will continue to verify whenever it is submitted for the same DID, unless another challenge is generated and overwrites the stored value. The token is therefore a replayable bearer artifact rather than a one-time proof. ### Attack Path 1. A verifier generates a challenge for a DID. 2. The legitimate DID holder signs it and submits the resulting JWS. 3. An attacker captures the token from command history, process telemetry, logs, clipboard data, terminal output, or another comm ...[truncated 951 chars]
Remediation
## Remediation Suggestions - Generate at least 128 bits of cryptographically secure random data, for example `crypto.randomBytes(32).toString("base64url")`. - Store an explicit expiration timestamp and reject expired challenges. - Atomically consume or delete the challenge immediately after successful verification. - Ensure concurrent verification requests cannot successfully consume the same challenge more than once. - Bind the signed value to the verifier, intended action, session identifier, issuance time, and expiration time. - Use constant-time comparison where practical for fixed-format challenge values. - Limit failed verification attempts and audit replay attempts. - Add tests proving that expired and previously used tokens are rejected.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/shared/utils.js:75
Finding
Private Keys and Authentication Tokens Are Accepted Through Process Arguments## Vulnerability Details **File Location**: `SKILL.md:37-47, 132-137`; `scripts/shared/utils.js:75-86` **Vulnerability Type**: Sensitive-data exposure through command-line arguments **Risk Level**: High ### Vulnerable Code ```markdown **Command**: `node scripts/createNewEthereumIdentity.js [--key <privateKeyHex>]` # Create identity from existing private key (with 0x prefix) node scripts/createNewEthereumIdentity.js --key 0x1234567890abcdef... # Create identity from existing private key (without 0x prefix) node scripts/createNewEthereumIdentity.js --key 1234567890abcdef... ``` ```markdown **Command**: `node scripts/verifySignature.js --did <did> --token <token>` node scripts/verifySignature.js --did did:iden3:billions:main:2VmAk... --token eyJhbGciOiJFUzI1NkstUi... ``` ```javascript function parseArgs() { const args = {}; for (let i = 2; i < process.argv.length; i++) { if (process.argv[i].startsWith("--")) { const key = process.argv[i].slice(2); const value = process.argv[i + 1]; args[key] = value; i++; } } return args; } ``` ### Technical Analysis The documented and implemented interfaces place existing Ethereum private keys and signed authentication tokens directly in `process.argv`. Depending on the operating system and execution environment, process arguments may be visible through process inspection facilities, automation logs, shell history, audit systems, crash reports, CI/CD logs, or agent tool-call transcripts. Even if process listings are restricted to the same account, other processes operating under that account may still obtain the values. The risk is particularly severe for `--key`, which exposes a long-lived private key. The JWS token may also remain reusable because challenges are not consumed after verification. ### Attack Path 1. A user follows the documented command and supplies an existing private key w ...[truncated 975 chars]
Remediation
## Remediation Suggestions - Remove private-key and token values from command-line interfaces. - Read secrets from protected standard input without terminal echo, an inherited file descriptor, or an operating-system secrets store. - If file input is supported, require restrictive ownership and `0600` permissions and clearly warn against persistent plaintext files. - Redact secrets from all error messages, telemetry, and agent execution logs. - Recommend creating a new key internally rather than importing an existing high-value wallet key. - Separate blockchain asset keys from agent identity keys to reduce compromise scope. - Invalidate authentication tokens after one successful use and enforce short challenge expiration. - Update all examples and Skill instructions so users are not encouraged to place secrets in shell commands.

T08 · Insecure Dependencies

Warning
Location
README.md:33
Finding
Installation Instructions Execute a Mutable Latest Package Version## Vulnerability Details **File Location**: `README.md:33-35` **Vulnerability Type**: Unpinned remote package execution and supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```markdown 1. Install the skill: npx clawhub@latest install verified-agent-identity ``` ### Technical Analysis The installation instructions invoke `npx` with the mutable `@latest` tag. `npx` can download and execute package code from the configured npm registry. The effective code executed by this instruction can therefore change after the reviewed Skill version is published. The project's application dependencies have a lockfile containing resolved package URLs and integrity hashes, but that lockfile does not pin or authenticate the separate `clawhub@latest` installer command. A malicious future release, maintainer-account compromise, or registry compromise could consequently execute arbitrary code during installation. No evidence was found that the currently reviewed project intentionally retrieves and executes a malicious payload. The issue is the unsafe, mutable trust boundary created by the documented installation method. ### Attack Path 1. An attacker compromises the `clawhub` publishing account, package distribution path, or future `latest` release. 2. The attacker publishes a package containing a malicious lifecycle script or executable. 3. A user follows the README and runs `npx clawhub@latest install verified-agent-identity`. 4. `npx` downloads and executes the attacker-controlled latest package. 5. The malicious installer runs with the invoking user's privileges and can access the user's files, environment variables, network, and identity storage. ### Impact Assessment Successful supply-chain exploitation can result in arbitrary code execution with the privileges of the user performing installation. This may expose private keys in `$HOME/.openclaw/billions`, environment secrets, project files, and any other res ...[truncated 200 chars]
Remediation
## Remediation Suggestions - Replace `@latest` with an audited exact version. - Publish and verify integrity digests or signed release artifacts. - Prefer a reproducible installation process based on a committed lockfile. - Document the expected package publisher, version, checksum, and verification procedure. - Avoid executing install-time lifecycle scripts where possible; otherwise review and explicitly authorize them. - Use a restricted environment for installation with no access to production secrets or existing identity keys. - Establish dependency monitoring and a controlled release process for updating the pinned installer version.
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (37)

Credential Access

High
Category
Privilege Escalation
Content
| `identities.json`  | Identity metadata                                                                  |
| `defaultDid.json`  | Active DID and associated public key                                               |
| `challenges.json`  | Per-DID challenge history                                                          |
| `credentials.json` | Verifiable credentials                                                             |

There are several ways of storing private keys, to enable master key encryption as described in the **KMS Encryption** section below.
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The advertised purpose is identity linking and verification, but the documentation also exposes local key-management behavior, including storage of private keys and retrieval/import semantics not clearly surfaced in the high-level description. This mismatch is dangerous because users or orchestrators may approve the skill for verification tasks without realizing it also handles long-lived secret material locally, materially increasing compromise risk.

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
entity
description: Billions decentralized identity for agents. Link 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"] } } }
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).

Missing User Warnings

High
Confidence
96% confidence
Finding
The skill instructs users to create identities and link them before prominently warning that sensitive identity data, including potentially plaintext private keys, will be stored locally. This is dangerous because users may initialize the system without understanding that highly sensitive secrets are being persisted on disk, increasing the chance of credential theft or unsafe deployment in shared environments.

Missing User Warnings

High
Confidence
98% confidence
Finding
Documenting use of --key with a raw private key encourages passing secret material directly on the command line, where it can be exposed through shell history, process listings, audit logs, and agent traces. In an agent environment, this is especially risky because prompts, commands, and execution telemetry are often logged centrally, turning a one-time import into durable secret leakage.

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
90% confidence
Finding
The skill documentation identifies a local directory containing private keys, credentials, identity metadata, and profiles, confirming that the skill manages credential material with meaningful value to attackers. In context, this is dangerous not because merely naming the file is malicious, but because the skill's design centralizes sensitive artifacts in a predictable location and even permits plaintext private-key storage under some configurations.

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
ws 8.18.0 is flagged for uninitialized memory disclosure and memory exhaustion DoS, both relevant to network-facing websocket consumers. In an agent identity skill that may communicate with external services, a vulnerable websocket stack increases risk of denial of service or unintended data leakage if those code paths are used.

Known Vulnerable Dependency: brace-expansion==2.0.2 — 4 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-33750 (brace-expansion: Zero-step sequence causes process hang and memory exhaustion); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro) +1 more

High
Category
Supply Chain
Confidence
88% confidence
Finding
brace-expansion 2.0.2 is associated with multiple denial-of-service conditions involving pathological expansion behavior. Although often used in tooling rather than request handling, its presence is still a valid dependency risk because attacker-controlled patterns in reachable code paths can trigger 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
95% confidence
Finding
fast-uri 3.1.0 is reported vulnerable to host confusion and SSRF-related parsing issues, which are especially concerning in software that may fetch remote identifiers, registries, or DID documents. If attacker-controlled URIs are processed, parser discrepancies can bypass allowlists or redirect backend requests to unintended hosts.

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 fragmented websocket traffic, a meaningful risk for any exposed websocket endpoint or client processing attacker-controlled peers. This can allow relatively cheap remote denial of service against long-lived agent or identity service processes.

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
90% confidence
Finding
underscore 1.13.6 is reported vulnerable to unbounded recursion in flatten and isEqual, which can crash or hang processes on crafted nested structures. In agent ecosystems that may process remote JSON-like objects, this can become a practical denial-of-service vector if underscore utilities are reachable.

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
97% confidence
Finding
undici 5.29.0 is associated with multiple serious HTTP parsing and smuggling issues, including request/response smuggling and queue poisoning. In an identity-verification skill that may contact registries, DIDs, or proof services over HTTP, these flaws materially raise the risk of SSRF, request confusion, cache poisoning, or data integrity issues.

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 affected by websocket memory disclosure and fragmentation-based memory exhaustion issues, both relevant to any networked agent component. Because the skill concerns decentralized identity and may maintain external websocket or RPC connections, this dependency is more dangerous than in a purely local tool.

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
89% confidence
Finding
Credential data is persisted to `credentials.json` via file storage, exposing potentially sensitive attestations and identity-linked metadata on disk. In the context of an agent identity system, these records can reveal user identity attributes, relationships, and proof inputs, enabling privacy loss or facilitating impersonation when combined with stolen keys.

Missing User Warnings

High
Confidence
98% confidence
Finding
When no master key is available, _encodeEntry stores privateKeyHex directly on disk under provider='plain'. This creates a silent insecure fallback for highly sensitive cryptographic material, so any local compromise, backup leakage, container escape, or accidental file exposure immediately reveals private keys. In an identity/authentication skill, exposure of these keys can enable impersonation, fraudulent attestations, and persistent account takeover.

Missing User Warnings

High
Confidence
99% confidence
Finding
The list() method returns alias together with the full private key value for every stored entry, effectively turning a metadata/listing operation into bulk secret exfiltration. Any caller with access to this API can retrieve all private keys at once, which is especially dangerous in an agent identity system because stolen keys allow impersonation and unauthorized proof generation.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The README instructs users to execute `npx clawhub@latest install ...`, which pulls and runs the latest package version at install time rather than a reviewed, pinned release. If the upstream package is compromised or a breaking/malicious release is published, users could execute attacker-controlled code during installation.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
This second installation example repeats execution of `npx clawhub@latest`, creating the same supply-chain risk: users are told to run whatever code is current on npm at that moment. In an agent-install context, that code may gain access to local files, credentials, or configuration during setup.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The README states that private keys are stored in plaintext when `BILLIONS_NETWORK_MASTER_KMS_KEY` is not configured, but this is not surfaced as a prominent warning before users are told to create identities. In a credential and DID-management skill, this increases the chance that users generate long-lived authentication keys that are left unencrypted on disk, enabling local compromise or accidental disclosure.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill explicitly invokes Node scripts that perform networked identity operations and access sensitive local state under $HOME/.openclaw/billions, but it declares no tool scope or permission boundaries. In an agent setting, missing explicit permissions increases the chance that the skill is invoked with broader-than-necessary capabilities, making unintended network calls or secret access harder to constrain or audit.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The activation guidance is broad enough to match common identity, authentication, JWT, and signature-related requests, which could cause an agent to invoke this skill in situations beyond the user's intent. Because the skill can create identities, sign challenges, and interact with sensitive local identity storage, overbroad triggering raises the chance of unnecessary cryptographic actions or disclosure-related side effects.

Missing User Warnings

Medium
Confidence
80% confidence
Finding
This code persists a newly created DID, public key, and default-status flag via `didsStorage.save(...)`, which is a file or storage write affecting user data. The script includes comments for developers but no confirmation prompt, print/log notice before saving, or other user disclosure around this persistence step.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The code sends the full authorization request payload to an external URL shortener, which may include sensitive identity-verification metadata such as verifier details, callback information, and proof request scope. In an identity-linking skill, forwarding this data to a third party without explicit user disclosure or minimizing the shared content creates a privacy and trust risk, and could expose correlation data or enable logging by the shortener service.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This code initializes key providers backed by `KeysFileStorage("kms.json")`, which means private key material for agent identity is persisted to a local file. In an agent identity skill, these keys are highly sensitive because compromise enables impersonation, proof generation, and unauthorized use of linked identities; storing them unencrypted and without safeguards materially increases theft risk.

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
94% confidence
Finding
The lockfile pins uuid 13.0.0, which is reported vulnerable to a missing buffer bounds check in v3/v5/v6 when a caller supplies a buf argument. In a dependency manifest this is a real supply-chain exposure even though exploitability depends on application code paths reaching those APIs with attacker-influenced inputs.

Static analysis

No suspicious patterns detected.