T09 · Insecure Skill Coding Practices
- Location
SKILL.md:1245- Finding
Unverified x402 Payment Proof Is Accepted as Authorization for Escrow Creation
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 1245-1274
Vulnerability Type: Missing cryptographic verification and replay protection
Risk Level: High
Classification:T09: Insecure Skill Coding PracticesVulnerable Code
python def translate_request(self, request: ProtocolRequest) -> dict: proof_header = request.headers.get("X-PAYMENT-PROOF") if not proof_header: raise ValueError("No payment proof in request") proof = json.loads(proof_header) payer_id = proof.get("payer_agent_id", f"x402:{proof['tx_hash'][:16]}") return { "tool": "create_escrow", "inputs": { "payer_agent_id": payer_id, "payee_agent_id": self.agent_id, "amount": str(proof["amount"]), "description": f"x402 payment. TX: {proof['tx_hash']}", "escrow_type": "standard", "metadata": json.dumps({ "protocol": "x402", "tx_hash": proof["tx_hash"], "facilitator": self.facilitator_url, }), }, "metadata": { "tx_hash": proof["tx_hash"], "resource_path": request.path, }, } def handle(self, request: ProtocolRequest) -> ProtocolResponse: """Full request lifecycle: translate, execute, translate back.""" operation = self.translate_request(request) gh_response = self.client.execute( operation["tool"], operation["inputs"] ) return self.translate_response( gh_response, operation.get("metadata", {}) )Technical Analysis
The adapter treats the contents of the attacker-controlled
X-PAYMENT-PROOFHTTP header as authoritative. It parses the header and directly uses the claimed payer identity, transaction hash, and amount to create a GreenHelix escrow.No validation is performed to establish that:
- The transaction e ...[truncated 2380 chars]
- Remediation
View remediation
Remediation Suggestions
- Verify every proof with a trusted, allowlisted x402 facilitator before creating an escrow or releasing paid content.
- Perform cryptographic verification locally where the protocol supports it rather than relying exclusively on a remote assertion.
- Bind the verified proof to all security-relevant fields:
- Payer identity
- Recipient address or agent
- Amount and currency
- Resource identifier
- Network and chain ID
- Expiration time
- Transaction hash and nonce
- Require the verified amount to be equal to or greater than the server-defined price. Never derive the required price solely from the client-supplied proof.
- Store consumed transaction hashes or nonces atomically and reject replays.
- Require sufficient settlement confirmations before treating payment as final.
- Apply strict schema validation, size limits, and type checks to the proof header.
- Fail closed when facilitator validation is unavailable, malformed, or times out.
- Create escrow only after successful validation and return a payment error rather than HTTP 200 on verification failure.
- Add tests covering forged signatures, recipient mismatch, amount mismatch, expired proofs, wrong networks, malformed JSON, and replayed transactions.
