CAN Studio — certified CAN-bus analysis

A steering ECU claimed 940.5°. The wheel stops at 500. Watch it get caught — and named.

A vehicle-network monitor that doesn't score frames with a confidence — it proves each one NORMAL, ANOMALY, or REJECT and cites the exact CAN invariant it checked. Real Toyota RAV4 frames, decoded and verified in microseconds, deterministic to the bit.

can0 · Toyota RAV4 opendbc-shaped DBC 0 normal · 0 anomaly · 0 reject · peak 0.0 µs
Anomaly — proven, not guessed

Every attack, its frame, and the rule that named it

Four injections. Four proofs.

Each is a real candump frame decoded and proven to break one named invariant — never a black-box score. The verdict strings below are verbatim from the vulcan can CLI.

Details

The honest floor, the worst number, and the whole rulebook

A tool you can put in a safety case has to show its floor and its failure mode, not just its highlight reel. It's all here — expand what you want to inspect.

The honest floor — what NORMAL and REJECT actually mean

NORMAL isn't the absence of a flag — it's a completed proof of conformance. A clean RAV4 window, every applicable invariant proven to hold (counts grow per-ID as each cadence window accrues):

frame 1  0x0B4 SPEED  NORMAL — all 5 invariants hold
frame 3  0x0B4 SPEED  NORMAL — all 6 invariants hold
frame 8  0x0AA WHEEL_SPEEDS  NORMAL — all 5 invariants hold

REJECT is reserved for the genuinely uncheckable — ask it something outside the CAN claim grammar and it refuses rather than bluff. (An unknown arbitration id is a proven ANOMALY, not a shrug.)

query "this frame is beautiful" → REJECT — subjective marker: 'beautiful'
query "the door is open" → REJECT — objective but not a CAN claim
Full disclosure — the same detector on 53,802 real frames

The scenarios above are proofs against a curated DBC. This is the detector's first run on a real, nominal on-road capture (comma2k19, Toyota RAV4). No injected attacks — so every flag here is a false positive, and we say so.

Verdict distribution

VerdictCountShare
NORMAL21,57340.1%
ANOMALY32,22959.9%
REJECT00.0%

Anomalies by first-failing invariant

The number that matters: 40.8% false positives on known-DBC ids. The catalog was tuned on synthetic data and is too strict for a messy real bus — the open DBC maps only 31 of the 90 ids seen, so undocumented-but-benign ECUs trip valid_id_whitelist by construction, and real timing jitter over-trips cadence. Every verdict is still a sound proof against the catalog; the fix is a baseline-observed whitelist and measured cadence bands, not a softer model. That gap is tracked openly.

The invariant catalog — the whole rulebook, in plain sight

There is no hidden model weight deciding a verdict. Every frame is checked against this fixed, ordered catalog of decidable CAN invariants; the first one that fails names the anomaly.

The RAV4-subset DBC these invariants are derived from
BO_ 180 SPEED: 8 SG_ SPEED : 0|16@1+ (0.01,0) [0|655.35] "km/h" BO_ 170 WHEEL_SPEEDS: 8 SG_ WHEEL_SPEED_FR : 0|16@1+ (0.01,-67.67) [0|250] "km/h" BO_ 37 STEER_ANGLE_SENSOR: 8 SG_ STEER_ANGLE : 3|12@0- (1.5,0) [-500|500] "deg" BO_ 452 ENGINE_RPM: 8 SG_ RPM : 8|16@1+ (0.78125,0) [0|16383.75] ""