Skip to content

The security engine
tuned for your codebase.

Tune V12 to your codebase. Investigate security findings with the source, a reproducible proof, and a concrete fix.

FindingsF-143
Open finding

PTP rollback lets a stale cancel release live risk

Properties

Status
Open
Severity
High
Owner
Tam Lund

Origin

Repository
northstar/execution
Run
Run #8
Commit
b6a770a84ef9c2d1a2d8e98042fe78f431f77e84

Slots at risk.rslines 59 to 66 leave a monotonic-time quarantine, but their generations come from quantized NIC PTP time. With the configured backward-step policy, B can reuse cancelled A’s slot and generation. A replayed FIX cancel for A then passes risk.rslines 76 to 83 and releases B’s reservation.

Risk admits C while B remains live: two 1m orders against a 1m cap. The bounded deterministic reproduction explores rollback, slot reuse and cancel replay in this crate—not a hardware or production trace. Calls are serialized; memory ordering cannot fix identity reuse.

northstar/execution/src/risk.rs
ShowHide 48 lines
49 }
50
51 pub fn reserve(&mut self, units: u64, clocks: ClockReading) -> Result<Ticket, RiskError> {
52 if units == 0 {
53 return Err(RiskError::ZeroUnits);
54 }
55 let next_total = self.reserved.checked_add(units).ok_or(RiskError::Capacity)?;
56 if next_total > self.cap {
57 return Err(RiskError::Capacity);
58 }
59 let slot_index = self.slots.iter().position(|slot| {
60 slot.units == 0 && clocks.monotonic_ns >= slot.reusable_at
61 }).ok_or(RiskError::NoSlot)?;
62 let slot = &mut self.slots[slot_index];
63 // PHC buckets are reused if the configured servo steps backward.
64 let generation = clocks.nic_ptp_ns / crate::clock::PTP_BUCKET_NS;
65 slot.generation = generation;
66 slot.units = units;
V12Run #8
Reuse waits on monotonic time, but identity comes from a quantized NIC PTP clock. After quarantine expires, a configured backward servo step can give B the exact slot and generation previously assigned to A.
67 self.reserved = next_total;
68 Ok(Ticket { slot: slot_index, generation })
69 }
70
71 /// A confirmed venue cancel, including a later FIX replay of that report.
72 pub fn cancel_ack(&mut self, ticket: Ticket, clocks: ClockReading) -> Result<bool, RiskError> {
73 let Some(slot) = self.slots.get_mut(ticket.slot) else {
74 return Ok(false);
75 };
76 if slot.units == 0 || slot.generation != ticket.generation {
77 return Ok(false);
78 }
79 let reusable_at = clocks.monotonic_ns.checked_add(QUARANTINE_NS)
80 .ok_or(RiskError::ClockOverflow)?;
81 self.reserved -= slot.units;
82 slot.units = 0;
83 slot.reusable_at = reusable_at;
V12Run #8
A replayed cancel for A now matches live B. It releases B’s reservation without cancelling B at the venue. C can consume the freed budget: two 1m live orders against a 1m cap. Exclusive access does not prevent identity reuse.
84 Ok(true)
85 }
86}
northstar/execution/tests/temporal_aba.rs
PoC
northstar/execution/src/risk.rs
Fix+3−2
V12Run #8
Advance the retained slot generation, never a clock reading. checked_add refuses reuse on exhaustion before changing the reservation. Within this slab lifetime, an old ticket cannot name a later occupant; a restart must establish a fresh FIX epoch.
ShowHide 61 unchanged lines
62 let slot = &mut self.slots[slot_index];
63 // PHC buckets are reused if the configured servo steps backward.
64 let generation = clocks.nic_ptp_ns / crate::clock::PTP_BUCKET_NS;
+ // Slot identity advances independently of both clocks.
+ let generation = slot.generation.checked_add(1)
+ .ok_or(RiskError::GenerationExhausted)?;
65 slot.generation = generation;
66 slot.units = units;
ShowHide 20 unchanged lines

Securing the code behind systems that cannot afford to fail.

The proof is
in the findings.

Security research from V12, with the technical details behind the findings.

All research

Read the inbox
at any commit.

Each repository has its own inbox. Open main, a pull request, or a commit from its history. Findings stay tied to the code V12 reviewed, so you can compare their evidence across revisions.

Explore the inbox

Tune the engine
to your code.

A Tune tells V12 what the code does, the rules it must enforce, who is allowed to do what, past issues, and what each review should look for.

Explore a Tune
TunesClock domains & epochs
Tam Lund
Document Findings Runs

Clock domains & epochs

  • Overview
  • Rules
  • Access
  • Past issues
  • Tune intent

Rules

A slot's generation must advance on every reuse, independently of clocks. Monotonic time bounds quarantine; it does not establish order identity. The NIC PTP clock may step backward under the configured resynchronization policy. Quote deadlines must retain their clock and calibration domain. Accept a risk snapshot only from one stable, even publication sequence. Detect feed gaps across sequence wrap. Keep exposure reserved until a venue acknowledges the terminal order state. Every send, including failover replay, must respect the current kill-switch fence.

Repositories 1

northstar/execution
  • src/risk.rs
  • src/clock.rs

The engine meets you
where you already work.

Your agent connects to V12 over MCP, starts a review, follows the run to the end, and reads back each finding with its source, proof, and fix.

Explore the MCP server

Connect your agent

  • Claude Desktop OAuth
  • Cursor OAuth
  • Codex OAuth
  • VS Code OAuth
  • Windsurf OAuth
  • Your own agent Token
  1. 1 Paste the server URL into your agent
  2. 2 Sign in with OAuth or a token
  3. 3 Ask for a review in plain words

Server URL

Read the MCP docs

Your agent

v12 connected

Audit northstar/execution with V12 and walk me through the high-severity findings.

  • v12_audit_github
  • v12_watch
  • v12_findings

Run #8 · 1 finding · 1 high

  • High severity, F-143 PTP rollback lets a stale cancel release live risk

Every source
feeds the engine.

Run reviews manually, on pushes, or on pull requests. Bring alerts from Sentry, Datadog, Google Cloud, and Snyk into the same inbox, where V12 investigates the code.

Explore review runs

Select a source to see its event and the corresponding V12 finding. Connect Slack to send notifications to a Tune channel. Pull request reviews publish one GitHub check. V12 review shows F-143 from manual run #8; GitHub shows F-142 from push-triggered run #15.

V12 review

Full review

northstar/execution main Clock domains & epochs Tam Lund
V12 triages and investigates
Findings F-143

PTP rollback lets a stale cancel release live risk

Open High Tam Lund northstar/execution Clock domains & epochs Run #8 b6a770a84e
Slack notifications when connected
One check run per pull request

Get your codebase
in tune.

Start the engine Open app