NodusLab

Threat model

23 catalogued attacks, and the checkpoint trap.

Status: living document. Last revised 2026-09-01. Scope: the Nodus verification layer. The v1 coordinator's own security posture (no consumer auth, no rate limiting) is documented in ../nodus/README.md §Security and is out of scope here except where it interacts with verification.


1. Parties and trust

Party v1 assumption Target assumption
Consumer trusted to pay untrusted (may repudiate, may probe)
Coordinator fully trusted — schedules, meters, verifies, settles reduced: should not be able to silently forge settlement; eventually removable
Provider node trusted to self-report fully untrusted, rationally malicious
Hardware vendor n/a trusted only where a mechanism explicitly says so (L4)

The provider is the adversary this repository is about. We model it as rational and economically motivated, not arbitrarily Byzantine: it cheats when expected profit is positive, and it is capable of engineering effort proportional to the payoff. A rational adversary model is stronger guidance for design than a worst-case one, because it makes the defence a question of expected value rather than of impossibility.

Secondary adversary: colluding providers, since a network with replication or n-of-m voting is only as good as the independence of its replicas.


2. Attack catalogue

Each attack lists the claim it violates, whether Nodus v1 stops it, and the cheapest known defence. E00x references the experiment that measures the defence.

2.1 Output attacks (violate Claim A)

# Attack v1? Cheapest known defence
T1 Fabricate a plausible output, sign it not stopped replication / audit (E009), ZK (E001-006), TEE (E010)
T2 Return a cached output for a repeated prompt not stopped freshness nonce bound into the committed statement
T3 Return output from a smaller/cheaper model not stopped model-weight commitment + A-proof; or audit (E009)
T4 Return output from a different model entirely not stopped (model_version is self-attested) as T3
T5 Truncate generation early, claim full length partly (completion_tokens <= max_tokens) coordinator-side re-tokenisation of returned text

2.1a A threat that is also the default behaviour

E009-pre measured something that does not fit the usual attacker framing: on this machine, MLX's matmul called with float32 inputs on the Metal GPU returns results ~1,500× less accurate than the identical call on the CPU stream, with a constant relative error of 7.7 × 10^-4 — roughly 11 bits of effective mantissa. Threat T7 is therefore not only something an attacker does; it is what a mainstream accelerator path does by default, to providers with no intent to cheat.

Two consequences for this threat model:

  1. "Honest" is not well defined without a numeric contract. A job specification that names a model but not its numerical semantics does not determine a correct answer, so no verifier can be right about T7.
  2. The tolerance a network must grant its least precise honest hardware is the budget available to every attacker. This makes the loose-tolerance provider class strategically attractive to cheat from — a Sybil-adjacent incentive worth pricing in the CP-008 economic analysis.

2.2 Execution attacks (violate Claim B / E)

# Attack v1? Cheapest known defence
T6 Skip layers / early-exit, output "close enough" not stopped segment commitments + random segment challenge (E005, E009)
T7 Quantise more aggressively than specified not stopped MEASURED (E009-pre): tolerance-bounded audit does NOT work across devices — honest CPU/GPU divergence is within 3.7× of this attack's signature. Only exact/quantised-integer semantics, or numeric-class partitioning, defends
T8 Fabricate intermediate states to satisfy a checkpoint scheme n/a this is the central design trap — see §3
T9 Sub-contract the job to a cheaper third party and relay not stopped not clearly an attack; becomes one if locality/latency is priced
T10 Precompute the answer before the job is assigned not stopped unpredictable input / late-binding challenge

2.3 Metering attacks (violate Claim C / D)

# Attack v1? Cheapest known defence
T11 Inflate prompt_tokens in the attestation not stopped — settlement uses the attested value (coordinator/jobs.py:419-421) recompute from the prompt the coordinator itself sent (near-zero cost)
T12 Inflate completion_tokens not stopped, capped only by escrow recompute by tokenising the returned text
T13 Overstate duration_ms / throughput to win scheduling not stopped coordinator-side timing; reputation
T14 Game the CU-v0 benchmark (run it on better hardware than serves jobs) not stopped random re-benchmarking bound to job execution
T15 Claim the same computation for two jobs (duplicate billing) partly (per-job replay check) cross-job dedup on (input, model) commitments

2.4 Protocol and identity attacks (violate Claim O)

# Attack v1? Cheapest known defence
T16 Replay a previous result stopped (per-job) —
T17 Edit a result in transit stopped (HMAC) —
T18 Steal a node token and impersonate out of scope; token is a bearer credential asymmetric keys instead of HMAC
T19 Sybil: one machine, many node identities not stopped proof of distinct hardware — open problem, relates to Claim D
T20 Collude to pass n-of-m replication not stopped independent replica selection, stake, uncorrelated audit

2.5 Attacks specific to probabilistic verification

# Attack Defence
T21 Cheat only on jobs unlikely to be audited (strategic cheating) audit selection must be unpredictable to the provider at execution time; commit-then-reveal audit seed
T22 Cheat on a small fraction of jobs so expected loss < expected gain set penalty × detection probability > maximum gain — requires stake, so security becomes an economic parameter, not a cryptographic one
T23 Exit scam: accumulate reputation, then defect at scale bonded stake with delayed release; cap exposure per epoch

T22 is important enough to state as a design principle:

Under probabilistic verification, security is bounded by p_detect × penalty, not by soundness error alone. A verification layer without a slashable stake has no defence against a provider who cheats a little.

Quantified (E016, DERIVED). For layer-skipping under a one-random-layer audit: a provider skipping m of L layers saves m/L of the job's compute value V and is caught with probability m/L, so cheating is negative-expected-value when penalty·(m/L) > V·(m/L) — the m and L cancel:

A stake equal to the job's compute value suffices, at any depth and any level of greed.

Assumes a risk-neutral provider, a collectable penalty, a cheat that is detectable once audited (true under exact arithmetic), and an audit target chosen unpredictably after the provider commits — which requires a commitment to all layer outputs, e.g. a Merkle root. Nodus v1 lacks that commitment today.


3. The checkpoint trap

A tempting and false intuition, explicitly called out so nobody in this project rediscovers it:

"If checkpoint A and checkpoint B are both correct, the computation between them must have been performed correctly."

This is false. Commitment to two endpoint states constrains nothing about the path unless the transition itself is constrained. A prover who can obtain the correct state at B by any means (cache, a different algorithm, a smaller model that happens to agree, or simply having seen this input before) satisfies both checkpoints having skipped the work.

Checkpoints become meaningful only when combined with a constraint on the transition, i.e. one of:

  • a proof that state_B = F_segment(state_A) (a real segment proof — L5),
  • an interactive challenge over the segment that a cheating prover cannot answer without having the intermediate values (L3),
  • a binding that makes state B unpredictable without doing the work (freshness).

Checkpoints alone are an indexing structure, not a verification mechanism. Their value is that they make the challenge cheap: they let a verifier audit 1/N of the computation instead of all of it, once a transition constraint exists. Experiment 005 and 009 test exactly this distinction.


4. Mandatory question

Every mechanism proposed in this repository must answer, in its own analysis.md:

What can a malicious provider still get away with?

An answer of "nothing" is a red flag and will be treated as an unfinished analysis.