T09 · Insecure Skill Coding Practices
- Location
SKILL.md:88- Finding
Signed challenge does not cryptographically bind the complete registration context
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md:56-78andSKILL.md:88-105
Vulnerability Type: Incomplete cryptographic context binding and insufficient replay protection
Risk Level: MediumVulnerable Code
javascript const crypto = require("crypto"); const fs = require("fs"); const identityPath = `${process.env.HOME}/.openclaw/identity/device.json`; const identity = JSON.parse(fs.readFileSync(identityPath, "utf8")); const message = `clawkey-register-${Date.now()}`; const privateKey = crypto.createPrivateKey(identity.privateKeyPem); const signature = crypto.sign(null, Buffer.from(message, "utf8"), privateKey); const publicKeyDer = crypto .createPublicKey(identity.publicKeyPem) .export({ type: "spki", format: "der" }); const challenge = { deviceId: identity.deviceId, publicKey: publicKeyDer.toString("base64"), message, signature: signature.toString("base64"), timestamp: Date.now(), }; // POST challenge to https://api.clawkey.ai/v1/agent/register/initThe documented challenge construction also states:
markdown 1. **Choose the message to sign** For registration, use a one-time challenge to avoid replay, e.g.: - `clawkey-register-<unix_timestamp_ms>` 2. **Sign the message** with your Ed25519 **private** key. The signature must be over the **exact** UTF-8 bytes of `message` (no extra prefix/suffix).Technical Analysis
The Ed25519 signature authenticates only the
messagestring. It does not cryptographically bind the accompanyingdeviceId,publicKey, standalonetimestamp, protocol version, endpoint, or operation type.Consequently, the integrity of those unsigned fields depends entirely on undocumented server-side validation. If the server does not derive the device identity from the supplied public key and strictly validate every contextual field, an attacker possessing a captured valid request could attempt to replace ...[truncated 2253 chars]
- Remediation
View remediation
Remediation Suggestions
- Require the server to generate a cryptographically random, high-entropy nonce before registration or verification.
- Give each nonce a short expiration period, bind it to the intended endpoint and session, and atomically mark it as consumed after successful use.
- Sign a canonical payload containing at least:
- A fixed protocol domain, such as
clawkey.ai - Protocol version
- Intended operation, such as
register/initorverify/signature - Server-issued nonce
- Session identifier where applicable
deviceId- Public-key fingerprint
- One consistently generated timestamp
- A fixed protocol domain, such as
- Use deterministic serialization or a formally specified binary encoding so that client and server sign and verify identical bytes.
- Derive or validate
deviceIdfrom the authenticated public key rather than trusting an independently supplied identifier. - Generate the timestamp once and reuse the same value in both the signed payload and request metadata.
- Enforce a strict clock-skew window, reject expired requests, and maintain replay detection for all consumed nonces.
- Use distinct signed domains for registration and general signature verification to prevent cross-protocol reuse.
