Research · Security

Red-teaming our own detector

Dated September 7, 2026. A published evasion attack, run against LS-Stat's actual deployed weights — what evaded, what didn't, and a false start we caught before publishing the number.

All research

Latent-space defences — probes that read a model's internal activations to catch what it's about to do — have a published evasion result behind them. Bailey et al. (ICLR 2026) showed that an attacker with the probe's weights and gradient access to the underlying model can optimise an input that keeps its attack intact while steering its activation away from the probe's decision boundary, driving one such monitor's recall from 100% to 0% while the underlying jailbreak still succeeded roughly 90% of the time.

LS-Stat, Interocept's detection channel, is exactly this kind of probe. We'd cited that result as the reason we don't claim immunity. This is the write-up of the first time we actually ran the attack against our own detector, rather than assuming the bound applies and moving on.

The attack

A gradient search finds a short adversarial suffix — a handful of tokens appended after an injected instruction, inside the same tool-return content — that pushes the pooled activation vector across the probe's decision threshold. We built this against LS-Stat's exact deployed scoring function: the same per-layer z-scoring, the same fitted weights, the same averaging across the layer band that ships in production. Not an approximation of the defence — the defence itself, with the gradients turned on.

One design choice matters more than the mechanics: the suffix never touches the injected instruction. It's appended after it, in the same message, leaving the original attack text byte-for-byte intact. A record stays labelled as an exposure the whole time — LS-Stat's label is exposure, not compliance, so this is the strong, honest form of the question. A successful attack here means the payload is still sitting in context, completely unmodified, and the detector's score dropped anyway.

Two arms, not one

LS-Stat pools activations by averaging over the untrusted span. That's a detail worth stress-testing on its own, before crediting anything to the gradient search: averaging means appending any content dilutes the pooled vector, attack-optimised or not. If dilution alone were enough to evade detection, that would be a cheaper, more troubling finding than the one Bailey et al. describe — a free attack, no weights or gradients required.

So every sample was scored three ways, each through the real, unmodified scoring path — never a differentiable stand-in used only to guide the search:

  1. Baseline — the original record, no suffix.
  2. Neutral padding — a suffix of repeated filler tokens, same length as the optimised one, no gradient step taken.
  3. Gradient-optimised — the suffix after a fixed search budget.

What we measured

Sixteen held-out attacks the detector was already catching, at the same threshold we'd use in production (calibrated for a 1% false-positive rate on clean traffic):

ArmStill caught
Baseline (no suffix)16 / 16
Neutral padding, no optimisation15 / 16
Gradient-optimised suffix2 / 16

Padding alone barely moves the number — one evasion out of sixteen, consistent with dilution being a minor effect on its own. The gradient search is a different story: fourteen of sixteen attacks that the detector was catching cleanly evaded it once the suffix was actually optimised against the deployed weights, typically by a wide margin rather than a narrow miss.

That gap is the actual finding. It rules out the cheap explanation (“anything long enough would have worked”) and confirms the one the published literature predicts: this specific kind of white-box access is what defeats the probe, not incidental noise in how it pools activations.

This started as an eight-sample run; we doubled it on the same random seed — so the first eight attacks here are identical to that original run, extended with eight more. The rate held: still 88% evaded under the optimised attack. The padding control, if anything, got weaker (one evasion in sixteen instead of one in eight) rather than stronger. That's the direction you want a control to move as N grows if the finding is real.

A false start worth reporting

The first run of this measurement said the opposite — only one attack in eight evaded, a far weaker result. We don't think that number was wrong by luck; we found the two bugs that produced it before publishing anything.

Reproducing exactly how the deployed model tokenises its input turned out to matter more than expected: a well-intentioned attempt to avoid what looked like a duplicated start-of-text token silently detokenised the attack's own scoring one position short of what the real system computes. Combined with a search that stopped as soon as its own (slightly optimistic) internal score crossed the threshold, the two bugs together meant the search was, on most samples, barely running at all before declaring victory — a wrong number that still looked like a plausible one.

The fix was to stop trusting the search's own bookkeeping. The number above is the only one we'd stand behind: the suffix the search finds, decoded to literal text, spliced into the real message, and re-scored through the unmodified, production-shaped path — the same way we'd score anything else. The optimiser's internal running score is kept for debugging and is never the reported result.

What this changes, and what it doesn't

It doesn't change the honest claim we've made from the start: determinism means the enforcement layer can't be talked out of a decision once it's made, not that the decision underneath it can't be optimised against by an attacker holding the weights. This measurement is evidence for that limit, with a real number attached, not evidence against it.

It's also why enforcement doesn't rest on detection succeeding every time. A score is a signal, not a verdict — Latch, the layer that acts on LS-Stat's score, holds an uncertain call for review or denies it outright rather than trusting a number it hasn't calibrated confidence in. The finding above is the concrete argument for building it that way rather than betting everything on the probe.

What this is not: a settled bound. Sixteen samples, one random seed, one corpus, and a suffix optimised separately for each attack rather than one reusable suffix an attacker could deploy cheaply at scale. The rate holding steady (and the control moving the right direction) from eight to sixteen samples is a real robustness check, not a substitute for a wider run — still not enough to quote as a stable rate. Extending it — a shared suffix across attacks, longer sessions, the closed-model fallback mode that never exposes activations directly — is open work, and we'll publish what we find.