Back to skill

Security audit

Birth System Manager

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent local birth-identity and migration purpose, but it handles wallet keys, archives workspace data, and unpacks archives in ways that can expose secrets or overwrite trusted files.

Review this skill carefully before installing. It should only be used in a contained environment with non-valuable test wallets unless the code is changed to avoid plaintext private keys, stop printing secrets, restrict package contents, and validate migration archives before extraction.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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 (7)

T09 · Insecure Skill Coding Practices

Error
Location
unpack.js:40
Finding
Shell Command Injection Through User-Controlled Unpack Paths<![CDATA[ ## Vulnerability Details **File Location**: `unpack.js:14-16, 34-40, 117-121` **Vulnerability Type**: OS command injection **Risk Level**: Critical ### Vulnerable Code ```js const packagePath = process.argv[2]; const targetDir = process.argv[3] || process.env.HOME; ``` ```js try { execSync(`tar -xzf "${packagePath}" -C "${targetDir}"`, { stdio: 'inherit' }); console.log('✅ Package extracted\n'); } catch (error) { console.error('❌ Extraction failed:', error.message); process.exit(1); } ``` A second shell invocation uses another path derived from the target directory: ```js const migrationPath = path.join(targetDir, 'MIGRATION.md'); if (fs.existsSync(migrationPath)) { console.log('📖 Migration instructions found. Opening...'); console.log(''); try { execSync(`cat "${migrationPath}"`, { stdio: 'inherit' }); } catch (error) { console.error('Could not display migration guide'); } } ``` ### Technical Analysis Both `packagePath` and `targetDir` are command-line arguments and are interpolated into command strings passed to `execSync`. Because `execSync` executes through a shell, shell metacharacters and command substitutions contained in these values may be interpreted rather than treated as literal path characters. Surrounding a value with double quotes does not make this safe. Command substitution such as `$(command)` remains active inside double quotes, and an embedded quote can terminate the quoted argument. The later `cat` command provides a second injection point because `migrationPath` incorporates the attacker-controlled target directory. ### Attack Path 1. An attacker persuades the user or Agent to unpack a package using a crafted package path or target directory. 2. The crafted path contains shell syntax, such as command substitution or an embedded quote followed by another command. 3. `unpack.js` interpolates the value into the `tar` command string. 4. The system shell evaluates the injected syntax when `execSy ...[truncated 692 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not construct shell command strings from user input. - Invoke `tar` with an argument array and with shell processing disabled: ```js const { spawnSync } = require('child_process'); const result = spawnSync( 'tar', ['-xzf', packagePath, '-C', targetDir], { stdio: 'inherit', shell: false } ); if (result.error || result.status !== 0) { throw result.error || new Error(`tar exited with status ${result.status}`); } ``` - Replace the `cat` subprocess with `fs.readFileSync(migrationPath, 'utf8')`. - Resolve inputs with `fs.realpathSync` where applicable and enforce an approved target-directory policy. - Reject null bytes and paths outside the expected migration area. - Add regression tests using paths containing quotes, command substitutions, semicolons, spaces, and newlines. ]]>

T07 · Tool Hijacking and Spoofing

Error
Location
unpack.js:34
Finding
Unverified Migration Archive Can Overwrite Trusted Agent Content<![CDATA[ ## Vulnerability Details **File Location**: `unpack.js:34-61` **Vulnerability Type**: Untrusted archive extraction and trusted-tool replacement **Risk Level**: High ### Vulnerable Code ```js // Step 2: Extract package console.log('Step 2: Extracting package...'); try { execSync(`tar -xzf "${packagePath}" -C "${targetDir}"`, { stdio: 'inherit' }); console.log('✅ Package extracted\n'); } catch (error) { console.error('❌ Extraction failed:', error.message); process.exit(1); } // Step 3: Read clone marker console.log('Step 3: Reading clone marker...'); const markerPath = path.join(targetDir, 'clone-marker.json'); if (!fs.existsSync(markerPath)) { console.warn('⚠️ Clone marker not found. This might not be a birth pack.'); } else { const marker = JSON.parse(fs.readFileSync(markerPath, 'utf8')); console.log(`✅ Original Birth ID: ${marker.original_birth_id}`); console.log(`✅ Pack created: ${new Date(marker.pack_time).toISOString()}`); console.log(''); } // Step 4: Verify birth system console.log('Step 4: Verifying birth system...'); const birthSystemDir = path.join(targetDir, '.openclaw', 'birth-system'); if (fs.existsSync(birthSystemDir)) { console.log('✅ Birth system files found\n'); } else { console.warn('⚠️ Birth system not found\n'); } ``` ### Technical Analysis The package is extracted directly into the selected target directory before any package format, manifest, signature, archive member, path, link, or ownership validation occurs. The post-extraction checks only test whether a marker and birth-system directory exist. They do not authenticate the package or inspect the extracted code. A package can therefore contain attacker-controlled files under locations such as: - `.openclaw/birth-system/` - `.openclaw/workspace/skills/` - `.openclaw/workspace/` - Other paths accepted by the system `tar` implementation If these paths already exist, archive entries can replace trusted scripts or Agent content. Link entries and uns ...[truncated 1150 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Never extract an untrusted archive directly into the final destination. - First list archive members without extraction and reject: - Absolute paths. - Paths containing `..` components. - Symbolic links and hard links. - Device nodes, FIFOs, and other special files. - Files outside a strict migration allowlist. - Extract into a newly created private temporary directory. - Require a signed manifest containing every expected path, file hash, type, and size. - Verify the manifest and package signature before installation. - Present an overwrite plan and obtain explicit authorization before replacing existing files. - Install validated content atomically and preserve a rollback copy. - Apply restrictive permissions and ownership rather than trusting archive metadata. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
pack.js:18
Finding
Wallet Backup Password Is Disclosed Alongside Encrypted Key Material<![CDATA[ ## Vulnerability Details **File Location**: `pack.js:18, 29-37, 168-180, 190-198, 223-228, 370-376` **Vulnerability Type**: Hardcoded secret, secret disclosure, and ineffective encryption design **Risk Level**: Critical ### Vulnerable Code The code silently falls back to a public, hardcoded password: ```js const password = process.argv[2] || process.env.BIRTH_PACK_PASSWORD || 'default-secret-password'; ``` The password is used to protect the private key: ```js function encrypt(text, password) { const iv = crypto.randomBytes(16); const key = crypto.scryptSync(password, 'salt', 32); const cipher = crypto.createCipheriv('aes-256-cbc', key, iv); let encrypted = cipher.update(text, 'utf8', 'hex'); encrypted += cipher.final('hex'); // Prepend IV to encrypted data return iv.toString('hex') + ':' + encrypted; } ``` ```js if (birthData?.private_key) { const walletData = JSON.stringify({ birth_id: birthId, wallet_address: walletAddress, private_key: birthData.private_key, public_key: birthData.public_key, signature: birthData.signature, created_at: birthData.created_at }, null, 2); const encryptedWallet = encrypt(walletData, password); const encryptedPath = path.join(tempDir, 'wallet-backup.encrypted'); fs.writeFileSync(encryptedPath, encryptedWallet); } ``` The same password is embedded in a file added to the archive: ```js const instructions = `# OpenClaw Birth System - Migration Instructions ## Overview This package contains a complete OpenClaw instance with birth system tracking. Pack created: ${new Date(timestamp).toISOString()} Original Birth ID: ${birthId} ## Prerequisites - Node.js 22+ - Extracted password: ${password} ``` It is also inserted into a command example and printed to output: ```js node ~/.openclaw/birth-system/decrypt-wallet.js ${password} ``` ```js console.log(` 🔐 Password: ${password}`); ``` ### Technical Analysis The confidentiality of password-based encryption de ...[truncated 1643 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the hardcoded fallback and abort if no password or secure key source is supplied. - Obtain passwords from a no-echo interactive prompt or a protected secret provider. - Do not accept secrets through command-line arguments. - Never print the password or include it in archive files, instructions, logs, or generated commands. - Encrypt the entire migration archive rather than protecting only one wallet file. - Use an authenticated encryption mode such as AES-256-GCM or XChaCha20-Poly1305. - Generate and store a unique random salt with each encrypted object. - Use a memory-hard password KDF with reviewed parameters, such as scrypt or Argon2id. - Include a versioned encryption envelope containing the salt, nonce, KDF parameters, ciphertext, and authentication tag. - Provide password transfer guidance that uses a separate trusted channel. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
generate-birth-id.js:42
Finding
Ethereum Private Key Is Persisted in Plaintext<![CDATA[ ## Vulnerability Details **File Location**: `generate-birth-id.js:24-50, 66-70` **Vulnerability Type**: Plaintext storage of sensitive key material **Risk Level**: High ### Vulnerable Code ```js async function generateBirthId(isClone = false, parentId = null) { // Generate wallet const wallet = ethers.Wallet.createRandom(); const did = `did:ethr:${wallet.address}`; const now = Date.now(); let fullId = did; let cloneSuffix = null; if (isClone) { cloneSuffix = `-clone-${now}`; fullId += cloneSuffix; } // Create signature to prevent tampering const message = `BirthID:${fullId}|Created:${now}|Parent:${parentId || 'none'}`; const signature = await wallet.signMessage(message); return { birth_id: fullId, parent_id: parentId, clone_suffix: cloneSuffix, created_at: now, signature: signature, wallet_address: wallet.address, public_key: wallet.publicKey, // Store private key for verification (in production, this should be encrypted) private_key: wallet.privateKey }; } ``` ```js function saveBirthInfo(birthData) { fs.writeFileSync(BIRTH_INFO_PATH, JSON.stringify(birthData, null, 2)); } ``` ### Technical Analysis The generated private key is inserted directly into the general-purpose birth information object and serialized as plaintext JSON. The write does not request an explicit restrictive mode such as `0o600`. A private key is not required to verify a signature; only the public address and signature are needed. Retaining the private key in this configuration therefore creates unnecessary long-term exposure. The file is subsequently processed by migration code, increasing the number of components and backups that may encounter the secret. ### Attack Path 1. A user initializes the birth system. 2. The script generates an Ethereum wallet. 3. The raw private key is written to `~/.openclaw/birth-info.json`. 4. A local process, another user with applicable filesystem access, ...[truncated 446 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not store the raw private key in `birth-info.json`. - Store public identity metadata separately from secret key material. - Use an OS credential manager, hardware-backed key store, or standard encrypted Ethereum keystore. - If file-based storage is unavoidable: - Encrypt the key using authenticated encryption. - Require a user-supplied secret that is not stored with the ciphertext. - Create the file atomically with mode `0o600`. - Verify ownership and reject symbolic links. - Remove the private key immediately from in-memory configuration objects after signing where practical. - Rotate any key previously written by the vulnerable implementation. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
decrypt-wallet.js:78
Finding
Wallet Decryption Exposes the Full Private Key Through Output or Disk<![CDATA[ ## Vulnerability Details **File Location**: `decrypt-wallet.js:78-94`; `SKILL.md:83-86` **Vulnerability Type**: Sensitive information disclosure **Risk Level**: High ### Vulnerable Code The Agent-facing instructions explicitly prohibit returning the secret: ```md - When user says "decrypt wallet", "解密钱包", "show private key": Require password (env or ask). Run: node {baseDir}/decrypt-wallet.js ~/.openclaw/birth-info.json [password] Return ONLY wallet address and success message, NEVER show full private key. ``` The invoked script does the opposite: ```js // Option 1: Output to stdout (safe, doesn't write to disk) if (process.env.DECRYPT_OUTPUT_TO_FILE === 'true') { const outputPath = path.join(path.dirname(birthInfoPath), 'private-key-decrypted.txt'); fs.writeFileSync(outputPath, privateKey); console.log(`⚠️ Private key written to: ${outputPath}`); console.log(' Delete this file immediately after use!\n'); } else { console.log('🔐 Private Key:'); console.log('─'.repeat(60)); console.log(privateKey); console.log('─'.repeat(60)); console.log(''); console.log('💡 To save to file: export DECRYPT_OUTPUT_TO_FILE=true && node decrypt-wallet.js ...'); console.log(''); } ``` ### Technical Analysis By default, the full private key is printed to standard output. In an Agent environment, subprocess output may be captured before higher-level instructions can suppress it. It can consequently enter tool traces, chat transcripts, terminal logs, telemetry, or debugging records. The optional file-output mode writes the key without explicitly setting restrictive permissions and uses a predictable filename. It also leaves the secret on disk until manually deleted. Calling stdout output “safe” is incorrect for secret material, particularly in an AI Agent execution environment. ### Attack Path 1. A user asks the Agent to decrypt the wallet. 2. The Agent follows `SKILL.md` and invokes `decrypt-wallet.js`. 3. The script prints the co ...[truncated 764 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove all private-key output from stdout and stderr. - Return only the wallet address and a boolean verification result. - Avoid plaintext export entirely where possible; perform required signing operations inside the decryption process. - If export is an unavoidable advanced operation: - Require a separate explicit command and confirmation. - Create a unique file atomically with mode `0o600`. - Refuse symbolic-link destinations. - Avoid predictable filenames. - Provide secure deletion and key-rotation guidance. - Ensure Agent tool output redaction treats private-key formats as secrets. - Update documentation and tests to guarantee that successful decryption never emits the key. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
pack.js:332
Finding
Migration Package Copies Agent Workspace and Memory Without Confidentiality Protection<![CDATA[ ## Vulnerability Details **File Location**: `pack.js:332-349` **Vulnerability Type**: Excessive collection and plaintext packaging of sensitive Agent data **Risk Level**: High ### Vulnerable Code ```js // Add workspace (if exists) const workspaceDir = process.env.OPENCLAW_WORKSPACE || path.join(stateDir, 'workspace'); if (fs.existsSync(workspaceDir)) { addDirectory(archive, workspaceDir, '.openclaw/workspace'); console.log('✅ Added workspace'); } // Add skills (if exists) const skillsDir = path.join(workspaceDir, 'skills'); if (fs.existsSync(skillsDir)) { addDirectory(archive, skillsDir, '.openclaw/workspace/skills'); console.log('✅ Added skills'); } // Add memory (if exists) const memoryDir = path.join(workspaceDir, 'memory'); if (fs.existsSync(memoryDir)) { addDirectory(archive, memoryDir, '.openclaw/workspace/memory'); console.log('✅ Added memory'); } ``` The archive exclusion list does not provide a credential-focused allowlist: ```js const excludePatterns = [ '*.log', '*.cache', 'node_modules/**', '.DS_Store', '*.dSYM', '*.tgz', '*.tar.gz', 'backup*.tar.gz', 'tmp/**', 'temp/**', '.cache/**', '*.sqlite', '*.db' ]; ``` ### Technical Analysis The entire workspace is added to an ordinary gzip-compressed tar archive. Compression provides no confidentiality. Because the workspace is included recursively, the separate Skills and memory additions are redundant, but they confirm that these sensitive directories are intentionally within scope. The exclusion policy does not exclude common secret-bearing files such as `.env`, configuration tokens, credentials, API keys, private documents, transcripts, or arbitrary memory content. It also uses a blacklist rather than a minimal allowlist. Birth identity migration does not inherently require copying all Agent memory and workspace data, so this collection exceeds the least-data requirement. ### Attack Path 1. The user asks the Skill to create a migration package ...[truncated 648 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not include workspace or memory by default in a birth-identity migration. - Use a strict allowlist of files required for the stated migration function. - Require separate, explicit user consent for memory, workspace, and Skills. - Before packaging, show an inventory of included files and flag likely secrets. - Exclude `.env` files, credential stores, tokens, private keys, transcripts, and unrelated memory by default. - Encrypt and authenticate the entire archive using a secret kept separately from it. - Avoid adding the same directories multiple times. - Add package-size and file-count limits and reject symbolic links that resolve outside the approved source tree. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
clone-init.js:87
Finding
Clone Initialization Persists Changed Identity Data With a Stale Signature<![CDATA[ ## Vulnerability Details **File Location**: `clone-init.js:87-150`; also present in `fix-clone.js:119-177` **Vulnerability Type**: Fail-open cryptographic verification and identity-integrity failure **Risk Level**: Medium ### Vulnerable Code A new signed message is constructed: ```js // Create message for signature const message = `BirthID:${newBirthId}|Created:${newCreatedAt}|Parent:${originalBirthId}`; ``` If the key is unavailable or decryption fails, the old signature is reused: ```js } else if (birthData.encrypted_private_key) { // Try to decrypt using environment password const password = process.env.BIRTH_PRIVATE_KEY_PASSWORD; if (!password) { console.log('⚠️ Warning: BIRTH_PRIVATE_KEY_PASSWORD not set'); console.log(' Signature will be generated with existing signature.\n'); // Fallback: use existing signature pattern (not ideal, but works for display) signature = birthData.signature; } else { // Decrypt private key try { const decrypted = decryptPrivateKey(birthData.encrypted_private_key, password); const wallet = new ethers.Wallet(decrypted); signature = wallet.signMessageSync(message); } catch (decryptError) { console.log('⚠️ Warning: Failed to decrypt private key'); console.log(' Using existing signature pattern.\n'); signature = birthData.signature; } } } else { console.log('⚠️ Warning: No private key found'); console.log(' Signature will be generated with existing pattern.\n'); signature = birthData.signature; } ``` The changed data and stale signature are then persisted: ```js const newBirthData = { ...birthData, birth_id: newBirthId, parent_id: originalBirthId, type: 'clone', created_at: newCreatedAt, ancestors: ancestors, clone_suffix: cloneSuffix, message_for_signature: message, signature: signature, clone_initialized_at: new Date().toISOString() }; // Write updated birth info try { fs.writeFileSync(BIRTH_INFO_P ...[truncated 1895 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Fail closed whenever the new identity cannot be signed. - Never reuse a signature after modifying any signed field. - Verify the newly generated signature against the expected wallet address before writing the record. - Write updates atomically only after all validation succeeds. - Preserve the original file unchanged on signing or validation failure. - Require cryptographic evidence for parent lineage rather than accepting only a caller-provided string. - Standardize the encrypted-key format and KDF across generation, cloning, fixing, packing, and decryption code. - Add tests proving that missing passwords, incorrect passwords, malformed ciphertext, and signing errors do not modify identity state. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (36)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The description focuses on birth-system management, but the documented packaging behavior is broader and may archive workspace, skills, or memory content, creating a data exfiltration and oversharing risk. Packaging more than the user reasonably expects is dangerous because local archives often become transferable artifacts that can leak secrets, history, or other sensitive state.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The description focuses on birth-system management, but the documented packaging behavior is broader and may archive workspace, skills, or memory content, creating a data exfiltration and oversharing risk. Packaging more than the user reasonably expects is dangerous because local archives often become transferable artifacts that can leak secrets, history, or other sensitive state.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The description focuses on birth-system management, but the documented packaging behavior is broader and may archive workspace, skills, or memory content, creating a data exfiltration and oversharing risk. Packaging more than the user reasonably expects is dangerous because local archives often become transferable artifacts that can leak secrets, history, or other sensitive state.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The description focuses on birth-system management, but the documented packaging behavior is broader and may archive workspace, skills, or memory content, creating a data exfiltration and oversharing risk. Packaging more than the user reasonably expects is dangerous because local archives often become transferable artifacts that can leak secrets, history, or other sensitive state.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The description focuses on birth-system management, but the documented packaging behavior is broader and may archive workspace, skills, or memory content, creating a data exfiltration and oversharing risk. Packaging more than the user reasonably expects is dangerous because local archives often become transferable artifacts that can leak secrets, history, or other sensitive state.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The description focuses on birth-system management, but the documented packaging behavior is broader and may archive workspace, skills, or memory content, creating a data exfiltration and oversharing risk. Packaging more than the user reasonably expects is dangerous because local archives often become transferable artifacts that can leak secrets, history, or other sensitive state.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The description focuses on birth-system management, but the documented packaging behavior is broader and may archive workspace, skills, or memory content, creating a data exfiltration and oversharing risk. Packaging more than the user reasonably expects is dangerous because local archives often become transferable artifacts that can leak secrets, history, or other sensitive state.

Missing User Warnings

High
Confidence
99% confidence
Finding
The script writes sensitive wallet material, including a private key, to disk in JSON without any user-facing warning, encryption, or permission hardening. In the context of an agent skill, this is especially risky because users may not expect credential generation and storage, and any local attacker, backup system, or accidental file exposure could compromise the key.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
fs.chmodSync(envScriptPath, '0o755');
console.log(`✅ Environment script created: ${envScriptPath}\n`);

// Step 7: Display instructions
console.log('✨ Unpack completed successfully!\n');
console.log('Next Steps:');
console.log('  1. Source environment:');
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The README advertises a wallet decryption capability but does not clearly warn that this action may expose raw private key material in process output, terminal history, logs, screenshots, or copied text. In a skill centered on agent identity and Ethereum-backed cryptographic proof, that omission is materially risky because users may invoke decryption casually and irreversibly compromise the wallet used to assert identity.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill invokes local Node scripts and explicitly relies on environment variables such as BIRTH_PRIVATE_KEY_PASSWORD and IS_CLONE, but it does not declare any tool scope or permissions boundary. Missing scope declarations increase the chance that an agent can access environment-sourced secrets or execute behaviors beyond what operators expect, reducing reviewability and containment.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger phrases use broad natural-language matching such as "or similar," which can cause the skill to activate on unintended requests and run local scripts that create wallets, mutate identity state, or package data. Overbroad invocation is especially risky here because the actions are stateful and touch sensitive files and secrets.

Session Persistence

Medium
Category
Rogue Agent
Content
- When user says "birth init", "generate birth id", "出生认证", "初始化出生系统" or similar:
  Run: node {baseDir}/generate-birth-id.js
  This will generate a unique Birth ID for new instances, create an Ethereum wallet, and generate a cryptographic signature.
  If IS_CLONE=true is set, it will automatically generate a clone Birth ID.
  Return the generated Birth ID, wallet address, and signature verification status.
Confidence
82% confidence
Finding
Generating a persistent Ethereum wallet, birth identifier, and signature creates durable identity artifacts tied to the local environment. Even without network use, this introduces session persistence and potentially long-lived sensitive state that can be copied, packed, or later disclosed, making subsequent compromise more damaging.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The general activation clause is ambiguous and may cause the skill to engage for broad discussion of the birth system rather than clear execution requests. In this context, accidental invocation could expose identity information or initiate sensitive local operations under weak user intent signals.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The comments and workflow imply a fresh signature is created for the clone identity, but multiple fallback paths silently reuse the existing signature when decryption or key access fails. That can produce metadata that looks re-signed when it is not, weakening identity integrity and enabling spoofed or unverifiable clone lineage records.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The script reads either a raw private key or encrypted private key material from the local birth data and proceeds to use it without strong disclosure or guardrails. In this skill context, the file appears to manage agent identity state, so embedding or accessing private key material in ordinary application storage substantially increases the blast radius of local compromise or operator misuse.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The code decrypts a wallet private key and uses it directly in process memory based on an environment-supplied password. Even though this appears intended for legitimate clone initialization, handling signing keys this way increases exposure to credential theft via process inspection, logs, crash dumps, inherited environment variables, or accidental persistence in the birth-info file.

Session Persistence

Medium
Category
Rogue Agent
Content
clone_initialized_at: new Date().toISOString()
  };

  // Write updated birth info
  try {
    fs.writeFileSync(BIRTH_INFO_PATH, JSON.stringify(newBirthData, null, 2), 'utf8');
  } catch (error) {
Confidence
72% confidence
Finding
The script persists updated identity state back to ~/.openclaw/birth-info.json, potentially including sensitive fields inherited from the original object such as private_key or encrypted_private_key. In a system that tracks clone lineage and wallet-linked identity, long-lived local persistence can preserve sensitive material and metadata beyond the immediate operation, increasing exposure after host compromise.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The script intentionally reveals the decrypted private key either by printing it to stdout or writing it to a plaintext file on disk. In practice, stdout is commonly captured by terminal scrollback, shell history workflows, CI logs, remote session recording, and process supervisors, while disk output leaves a recoverable secret at rest; both materially increase the chance of wallet compromise.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The comment states stdout output is 'safe' even though the code prints the full decrypted private key. This is dangerous because it normalizes an unsafe handling pattern and may cause operators or downstream developers to expose wallet secrets in logs, recordings, or shared terminals under the false belief that the behavior is secure.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
console.log('\nUsage:');
    console.log('  node fix-clone.js <parent_birth_id> [--force]');
    console.log('\nOptions:');
    console.log('  --force    Skip confirmation if already a clone');
    console.log('\nExample:');
    console.log('  node fix-clone.js did:ethr:0xF80042413226cf4a5F1b7de458Cf0EEd19237662');
    console.log('\nTo find parent_id from a package:');
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Session Persistence

Medium
Category
Rogue Agent
Content
original_created_at: originalCreatedAt
    };

    // Write updated birth info
    try {
      fs.writeFileSync(BIRTH_INFO_PATH, JSON.stringify(newBirthData, null, 2), 'utf8');
    } catch (error) {
Confidence
88% confidence
Finding
The script rewrites ~/.openclaw/birth-info.json with sensitive identity material, including potentially a plaintext private key or decrypted-key-derived metadata, without any file-permission hardening, atomic write pattern, or secret minimization. On multi-user systems or weakly permissioned environments, this can expose long-lived credentials and allow identity tampering or wallet compromise if the file is read or replaced by another local process.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The manifest describes secure wallet decryption and full lineage tracking for clone parent-child relationships, but the code in this file only creates an Ethereum wallet, derives a DID-like birth ID, stores basic parent_id metadata, and verifies a signature. There is no wallet decryption logic and no family-tree or lineage traversal/storage beyond a single parent reference.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The script performs filesystem writes to birth-info.json and potentially SOUL.md without clear warning or confirmation. In an agent-skill setting, undocumented write behavior is more dangerous because it can silently alter user state, create tracking artifacts, or overwrite important files if environment-controlled paths point somewhere unexpected.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The script writes to SOUL.md in the workspace as a side effect unrelated to core birth-ID generation. Unexpected modification of user workspace files increases risk because an agent skill can alter project state outside its stated purpose, which can be abused for persistence, misleading metadata, or unauthorized file tampering.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.exposed_secret_literal

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
unpack.js:40

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
clone-init.js:96

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
fix-clone.js:128

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
generate-birth-id.js:49

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
pack.js:172