Back to skill

Security audit

Devtopia Identity

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent for wallet-backed identity, but it needs review because its private-key and authentication guidance could expose keys or produce insecure identity checks.

Review before installing or using this skill for real identities. Prefer encrypted keystore-file workflows and do not paste PEM private keys into command lines. Treat the challenge-proof examples as incomplete unless your verifier enforces fresh single-use challenges, expiration, audience/action binding, and clear token issuance. Confirm the external devtopia CLI and chain behavior before minting an identity because on-chain registration may be permanent.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:62
Finding
Plaintext Private Keys May Be Exposed Through Command-Line Wallet Import<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 62–69 **Vulnerability Type**: Plaintext secret exposure through command-line arguments **Risk Level**: High ### Vulnerable Code ```bash devtopia id wallet import <privateKeyOrKeystore> ``` ```text Accepts: - PEM-formatted private key: `-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----` - JSON keystore: `{"algorithm":"aes-256-gcm",...}` ``` ### Technical Analysis The documented wallet-import interface permits a PEM-formatted private key to be supplied directly as a command-line argument. Secrets passed this way may be exposed through: - Shell history files - Process listings and process-monitoring tools - Terminal session recording - CI/CD job logs - Command auditing and telemetry - Wrapper scripts that log their arguments The risk applies even if the imported key is subsequently encrypted because the key has already appeared in plaintext at the process invocation boundary. This behavior also conflicts with the statement at `SKILL.md:190` that the private key is “never exported in plaintext.” ### Attack Path 1. A user follows the documented syntax and passes a PEM private key directly to `devtopia id wallet import`. 2. The shell stores the command in history, or a local monitoring/logging system records the process arguments. 3. An attacker with access to the history, logs, process metadata, or recorded terminal session retrieves the plaintext key. 4. The attacker imports the key into another wallet or compatible signing tool. 5. The attacker signs proofs or transactions while impersonating the legitimate agent. ### Impact Assessment Disclosure of the private key grants the attacker the cryptographic authority associated with the wallet. Depending on how the identity is used, this may allow: - Agent identity impersonation - Forging challenge-response proofs - Unauthorized blockchain transaction signing - Unauthorized marketplace actions - Permanent compromise of the wallet-b ...[truncated 152 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not accept literal private keys through command-line arguments. - Accept a path to a protected key file instead, and validate that its permissions prevent access by other users. - Alternatively, read private-key material from masked interactive input or standard input. - Avoid environment variables for long-lived private keys because environments can also leak through diagnostics and process inspection. - Ensure imported key buffers are cleared from memory when no longer required. - Prevent sensitive values from appearing in errors, telemetry, audit logs, or debug output. - Update the documentation to use a safe interface, for example: ```bash devtopia id wallet import --keystore-file ~/.secure/identity-keystore.json ``` - If plaintext PEM import is essential, prompt for it interactively and document the operational risks explicitly. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/challenge-proofs.md:5
Finding
Challenge Proofs Are Incorrectly Described as Non-Replayable Without Verifier-Side Enforcement<![CDATA[ ## Vulnerability Details **File Locations**: - `SKILL.md`, lines 77–87 - `references/challenge-proofs.md`, lines 5–14 - `references/challenge-proofs.md`, lines 75–82 **Vulnerability Type**: Missing replay protection in the documented authentication protocol **Risk Level**: Medium ### Vulnerable Documentation ```text This creates a verifiable proof that: - You control the private key for your wallet - You signed the specific challenge text - Proof is timestamped and cannot be replayed ``` ```text 1. **Challenger** provides a challenge string (random, timestamped, or context-specific) 2. **Agent** signs the challenge with their private key → creates a proof (signature) 3. **Verifier** checks the signature against the agent's public key If valid, the signature proves: - You control the private key - You signed this specific challenge - The challenge cannot be replayed (contains nonce/timestamp) ``` ```text ## Security Properties ✅ **Non-replayable:** Each challenge is unique (includes nonce/timestamp) ✅ **Non-transferable:** Proof is specific to the challenge ✅ **Verifiable:** Public key proves ownership without revealing private key ✅ **Timestamped:** Proof includes generation time ``` ### Technical Analysis A signature proves that a private key signed a specific message, but it does not inherently prevent the same signed message from being submitted again. Replay resistance requires verifier-side state and policy, including: - A verifier-generated, cryptographically random nonce - A short expiration time bound into the signed payload - Validation of the intended verifier or audience - Validation of the authorized operation - Storage and one-time consumption of accepted nonces The documented command signs arbitrary caller-provided strings, including static examples such as `verify-task-12345`. The provided verifier only validates the signature. It does not check timestamp freshness, validate a nonce, bind the proof to a specific audienc ...[truncated 1284 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Define and enforce a canonical signed payload containing at least: - Protocol and payload version - Cryptographically random verifier-generated nonce - Issuance timestamp - Expiration timestamp - Verifier or audience identifier - Authorized action and resource - Agent or wallet identifier - Network or chain identifier where applicable The verifier must: 1. Generate the nonce using a cryptographically secure random-number generator. 2. Associate the nonce with the intended operation and identity. 3. Reject unknown, expired, or previously consumed nonces. 4. Mark the nonce as consumed atomically when the proof succeeds. 5. Enforce a short validity period with bounded clock skew. 6. Reject proofs intended for another audience, domain, or operation. 7. Sign and verify an unambiguous canonical encoding rather than concatenated free-form strings. Replace the unconditional “cannot be replayed” claim with an explicit statement that replay resistance depends on mandatory verifier-side freshness and nonce-consumption controls. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/challenge-proofs.md:55
Finding
Documented P-256 Proofs Are Incompatible With the EVM ecrecover Verification Example<![CDATA[ ## Vulnerability Details **File Locations**: - `SKILL.md`, lines 156–172 - `references/challenge-proofs.md`, lines 55–63 - `references/challenge-proofs.md`, lines 87–101 **Vulnerability Type**: Incompatible cryptographic algorithms and ambiguous signature encoding **Risk Level**: Medium ### Vulnerable Code The Skill specifies P-256 for key generation and signatures: ```text ### Key Generation - **Algorithm:** ECDSA P-256 (secp256r1) - **Key Size:** 256-bit - **Format:** PEM (PKCS#8) ### Encryption - **Cipher:** AES-256-GCM (authenticated encryption) - **IV Size:** 96 bits - **Auth Tag:** 128 bits (GCM mode guarantees authenticity + confidentiality) ### Signature - **Type:** ECDSA P-256 (secp256r1) - **Use Case:** Challenge-response proofs, transaction signing ``` The on-chain example uses EVM `ecrecover`: ```solidity // On-chain verification require( ecrecover(challenge, v, r, s) == agentWallet, "Invalid proof" ); // Execute transaction ``` The JavaScript example is: ```javascript const crypto = require('crypto'); function verifyProof(challenge, signature, publicKey) { const verifier = crypto.createVerify('sha256'); verifier.update(challenge); return verifier.verify(publicKey, signature, 'hex'); } // Usage const isValid = verifyProof( "verify-task-12345", "0x<signature-64-bytes>", "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----" ); console.log(isValid ? "✅ Proof valid" : "❌ Proof invalid"); ``` ### Technical Analysis EVM `ecrecover` recovers addresses from secp256k1 ECDSA signatures. It does not verify signatures produced by the documented P-256/secp256r1 keys. Therefore, a valid proof generated according to the Skill cannot be verified by the shown Solidity code. The Solidity example also fails to define: - How the challenge becomes the required 32-byte digest - Whether a domain prefix is used - The signature encoding - Canonicality requirements - How the P-256 public key maps to an EVM address The JavaScript ...[truncated 1821 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Select and document one canonical signature scheme for each supported verification environment. - If P-256 remains the required scheme, use an explicitly supported and audited P-256 verifier or applicable chain precompile rather than `ecrecover`. - If native EVM `ecrecover` is required, redesign the identity keys and proof format around secp256k1 and clearly document the migration and compatibility implications. - Specify the exact canonical message encoding, domain separation, hashing algorithm, and digest passed to verification. - Specify whether signatures use DER or IEEE P1363 encoding and reject non-canonical encodings. - Strip or validate hexadecimal prefixes before decoding; do not rely on ambiguous library defaults. - Explicitly bind the verified public key to the registered agent or wallet identity. - Validate signature component ranges and enforce low-S canonicality where applicable. - Publish executable cross-language test vectors containing messages, hashes, public keys, signatures, and expected verification results. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Session Persistence

Medium
Category
Rogue Agent
Content
```

This will:
1. Create or load a local wallet (if one doesn't exist)
2. Generate your public/private key pair (ECDSA P-256)
3. Sign the identity registration transaction
4. Mint your identity on Base chain (Chain ID 8453)
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The documentation makes a strong security claim that private keys are never exported in plaintext, yet elsewhere it explicitly supports importing raw PEM private keys. Even if this is an import rather than an export path, the claim is misleading and could cause users to handle highly sensitive key material less cautiously or paste plaintext keys into unsafe contexts.

File System Enumeration

Medium
Category
Data Exfiltration
Content
### "Keystore not found"
```bash
# Check if it exists:
ls -la ~/.devtopia/identity-keystore.json

# If missing, restore from backup:
devtopia id wallet import <backup-file>
Confidence
60% confidence
Finding
Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The documentation asserts that challenge proofs are non-replayable because challenges contain a nonce or timestamp, but the examples only show signing arbitrary static strings and do not define any enforcement, validation, or freshness requirements. In an identity/authentication skill, this can lead implementers to accept reusable signed challenges, enabling replay of previously captured proofs and weakening agent authentication guarantees.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The session authentication example instructs users to derive and later verify a token from the proof, but the documented proof format contains no token field or token issuance flow. This mismatch can cause insecure ad hoc implementations where developers invent unsound token extraction or treat signatures as bearer tokens without proper binding, expiration, or verification semantics.

Static analysis

No suspicious patterns detected.