
x402-validate
Add validation layer to x402, so ai agent don't pay for low effort response
Demo
About
What this project is x402_validate is a Chainlink CRE (https://docs.chain.link/cre) (Chainlink Runtime Environment) workflow that acts as a confidential, trust-minimized validation oracle for API responses. A caller asks: "call this API and check whether its response satisfies my private criteria" — and the workflow executes that check inside a hardware enclave so that neither Chainlink's node operators, nor network observers, nor other callers can see what's being validated or how. The core flow (main.ts) 1. Trigger: anyone can fire the public HTTP trigger with a payload of { api: { url, requestType, body }, validationFunction } — an API to call plus an arbitrary JavaScript snippet that must return a boolean verdict on the response. 2. TEE execution: the handler is registered with handlerInTee, so all logic runs inside an AWS Nitro enclave (Confidential Workflows, private beta), not on regular DON nodes. 3. Authenticated API call: before calling the target API, the workflow fetches an ed25519 private key (API_SIGNING_KEY) from the Vault DON — released only into attested enclaves — and signs {timestamp, body}. The API verifies this signature against the workflow's published public key, which proves the request genuinely came from this workflow, inside a TEE (the Vault DON's release policy stands in for raw attestation, since CRE doesn't expose enclave attestation documents to workflow code). 4. Validation: the caller's validationFunction is eval'd against the response (delivered base64-encoded, since the runtime lacks atob and text() mangles binary) and must return a boolean. 5. Result: the verdict is returned as the workflow result — note HTTP triggers are fire-and-forget, so callers get results via callback, not the trigger response. The demo application: color-gated image API mock-api.js is a stand-in protected API that serves one of two paint images at random (paint_high_small.png / paint_low_small.png), only to requests bearing a valid, fresh enclave signature (401/400 otherwise). The showcase validationFunction (in payload-color-validation.json) is a self-contained ~35KB PNG decoder: it base64-decodes the response, inflates IDAT chunks with an embedded copy of fflate, reverses PNG scanline filters, computes mean HSV saturation, and accepts only if it's above 0.44 — the high-color image (0.484) passes, the low-color one (0.402) is rejected. The point: a proprietary, non-trivial algorithm can run as caller-supplied data, invisible to everyone but the enclave. What the experiments established • Payloads can be encrypted client-side to a workflow x25519 public key (ECIES: ephemeral ECDH → HKDF → AES-GCM), decrypted only in-enclave via a Vault-DON-held private key (main-tee.ts) — including the validation function itself, keeping it private even from other callers. • CRE limitations found empirically: no CSPRNG in the WASM sandbox, no workflow-writable secrets (so no ZK-ceremony-style TEE-born persistent keys), no attestation API, 250KB HTTP response cap, and eval scope leaks that required AsyncFunction isolation.
How it's made
It uses chainlink CRE to run inside secure TEE to validate the api with validation function, nothing is reveal to either parties. The core is a TypeScript CRE workflow whose HTTP trigger handler is registered with handlerInTee, so the entire callback executes inside an AWS Nitro enclave rather than on Workflow DON nodes; callers POST a JSON payload naming an API (url, method, base64 body) plus a validationFunction string containing arbitrary JavaScript that must return a boolean verdict on the response. Before calling the API, the enclave fetches an ed25519 private key from the Chainlink Vault DON, which threshold-encrypts secrets and releases them only to attested enclaves, then signs the request body and timestamp so the receiving API can verify against the workflow's published public key that the call genuinely originated from this workflow inside a TEE. Because CRE never returns trigger responses synchronously, the workflow calls the API itself and the verdict flows back through the workflow result. The demo API is a small Node server that serves one of two paint images at random only to validly signed requests, and the showcase validation function is a self-contained 35KB string that base64-decodes the image response, inflates PNG