§ Security

Security & responsible disclosure

DISCLOSE

How to report a vulnerability

Email security@plumbtech.xyz. Please do not file a public GitHub issue. We acknowledge within 48 hours, and aim to patch within 7 days for critical issues. You will be credited in the release notes unless you request anonymity.

In scope: the gateway, worker, contracts, SDKs, explorer, and console. Out of scope: vendored dependencies (report upstream), DoS (we know), anything requiring physical access to the VPS.

RECEIPTS

Receipt signing threat model

Every chat completion is signed with ed25519 over a canonical v1 payload. The private signing key lives on the gateway box, not on-chain. An attacker with the signing key can forge historical receipts — we mitigate by rotating the key viaSettlement.setSigner() and publishing the public key registry in the SDK and explorer. Forgery after rotation is detectable because the signer_key_idwon't match any entry in the registry.

The server stores request_hash and response_hash, not raw prompt text. A client can verify a receipt without trusting the operator by re-hashing the request/response they sent and checking the ed25519 signature with verify_receipt.

MODES

Verification modes

vanilla — the server signs with its ed25519 key. This is what the hosted instance runs today. Trust rests on the operator not colluding with upstream providers to swap out responses.

tee-nitro / tee-sgx — planned. Receipts also carry a TEE attestation quote. Verifiers check both the ed25519 signature and the attestation — proving the signing process ran inside the named enclave.

zkml — deferred. Zero-knowledge proof of inference for small models, eventually paired with Pipe.

CHAIN

On-chain components

Contracts are deployed on Base Sepolia today. Settlement checkpoints batches of receipts as Merkle roots; HubRegistry attributes uploaded models; PipeOracle relays requests to an off-chain worker. All are verified on Blockscout; ABIs are pinned in the @plumb/contracts package.