Security & Privacy
What VDM Nexus protects, what it doesn't, and how to reason about the trust model.
VDM Nexus gives you cryptographic verifiability of what the model said, not cryptographic privacy of what you asked. Those are different properties. This page covers both — what we secure, what's private, and where the limits are.
Threat model
The signed-inference promise: given a receipt, a third party can verify that a specific LLM call happened with the parameters claimed. Three parties whose behavior we model:
| Party | What they could try | What stops them today |
|---|---|---|
| An agent | Lie about what the model returned | The receipt is hash-bound to the prompt + response. Recompute → mismatch detectable. |
| A man-in-the-middle | Modify the response in flight | TLS everywhere. Plus the response_hash binds the content. |
| Nexus itself | Issue fraudulent receipts (claim a call happened that didn't) | The receipt JSON is Ed25519-signed by the Nexus operator key (receipt.nexus_signature, v=2). The on-chain tx_signature independently anchors the payment. verifyReceipt from @vdm-nexus/x402 runs both checks. |
What's secured today
- Identity: Ed25519 keypair, the same primitive Solana uses
- Replay prevention: unique
tx_signatureconstraint oncredits_ledger; nonces table on/inference - Failure mode: route fails-closed if no facilitator is configured; no silent acceptance
- Transit: TLS everywhere
- Idempotency: repeating a paid call returns
409 payment_replay, not double-charge - Receipt integrity: hashes bind content; on-chain tx proves payment; Ed25519
signature by the Nexus operator key proves Nexus issued the receipt. Fetch the public
key at
GET /api/v1/operator-keyand verify withverifyReceiptfrom@vdm-nexus/x402. - Rate limiting: Upstash-backed sliding window — 30 requests/minute per IP on
/v1/chat/completions, 100 requests/minute per agent pubkey on both inference routes. 429 responses carryX-RateLimit-{Limit,Remaining,Reset}headers. Fails open with a one-shot warn log when Upstash env vars are absent. See Observability for the full event vocabulary. - Facilitator signing in HSM: the Ed25519 fee-payer key lives in
AWS KMS via
KMS.Sign(algorithmED25519_SHA_512). The private key never enters lambda memory. Derived address is asserted to matchNEXUS_DEPOSIT_ADDRESSat startup; mismatch fails-closed. Live on Solana mainnet and devnet with the same code path. See Self-host the facilitator.
Mainnet hardening switches
Three operator-controlled env-vars bound real-USDC exposure on
/v1/chat/completions. None require a code change or redeploy — flip in
the Vercel dashboard and the next request reads the new value.
| Switch | Effect | Default |
|---|---|---|
NEXUS_MAINNET_ENABLED=false | Fails-closed on every mainnet request with 503 mainnet_disabled. Testnets stay reachable. | Mainnet enabled |
NEXUS_MAX_PRICE_USDC | Hard ceiling on the flat 402 price. Route refuses to issue a challenge above the cap. | 0.10 USDC |
NEXUS_ALLOWED_AGENTS | Comma-separated payer pubkey allowlist for mainnet only. Non-listed mainnet payers get 403 agent_not_allowed. | Unset (allowlist disabled) |
These are the incident-response surface. See Safe-mainnet switches for the recommended flip sequence and the structured log events each switch emits.
A SOL fee-payer balance probe runs on Vercel Cron every 5 minutes
(/api/v1/ops/sol-balance) and emits sol_balance.low / .critical warn
and error events when the wallet drops below 0.10 / 0.02 SOL. Pair with a
log drain for push notifications.
What's NOT secured yet (and tracked)
- Independent security audit. ~2000 lines of TypeScript handling real USDC. Deferred until first revenue per founder decision (see roadmap). Roadmap item, Horizon 1.
- Per-region failover for the facilitator. Single AWS region today — a region outage stalls settlement. Multi-region KMS + fee-payer is a future hardening item. Roadmap item, Horizon 2.
- Operator economic security. Today the facilitator's behavior is on the operator's honor system. Future operator staking + slashing makes fraud expensive. Token-utility item, Horizon 3.
Privacy: what we store and don't store
What we keep in the database per call:
inference_logs:
agent_pubkey — the payer's pubkey (already public on-chain)
upstream — "openrouter"
model — e.g. "openai/gpt-4o-mini"
prompt_tokens — count, not content
completion_tokens — count, not content
cost_usdc — upstream's reported cost
latency_ms — server-side latency
status — success or error
request_nonce — tx signature (for idempotency)What we do NOT keep:
- The prompt text itself
- The response text itself
- Any IP address or location data
- Any user-agent or device fingerprint
The receipt itself contains hashes of the prompt and response, not the content. The agent is the sole keeper of the actual prompt/response strings. If you lose them, you can no longer verify the receipt — that's by design.
Privacy: what's NOT private
Being honest about the limits:
- Prompts go through the upstream provider unmasked. Today the model runs on OpenRouter's network, which routes to OpenAI/Anthropic/etc. They see the full content. Their logging and training policies are theirs. Until we add TEE / ZKML upstream providers, this is unavoidable.
- Solana payments are public. Anyone watching the chain knows which wallets paid the Nexus deposit address, when, and how much. The content stays private; the usage pattern doesn't.
- Agent pubkey is permanent. Once observed, all of that agent's Nexus calls are linkable under that pubkey. No mixing built in.
How to reason about this for your use case
| If you need... | What to do |
|---|---|
| Proof of what the model returned, for audit | Today's Nexus is enough — receipts + tx_signature |
| Privacy of prompt content from Nexus | Already done — we don't store prompt text |
| Privacy of prompt content from the model provider | Wait for TEE / ZKML upstream support, or self-host |
| Unlinkability across calls | Rotate agent pubkeys per use case |
| Cryptographic proof Nexus itself issued the receipt | verifyReceipt from @vdm-nexus/x402 v0.2 — shipped |
The honest summary
Nexus today is strong on verifiability and integrity (hash-bound content, operator-signed receipts, on-chain settlement), decent on availability (self-hosted facilitator removes a third-party dependency), and explicitly not a privacy product for content sent to the model. If privacy of prompt content is the requirement, signed inference alone is the wrong tool — we'd need to add a private-inference upstream first, which is a Horizon 3+ roadmap item.
Reporting security issues
Please don't open public GitHub issues for security problems. Email
dennis@vdmnexus.com with details. We'll respond within 48 hours.