"I reported an F1 of 0.96. Then someone hid the answer key I had been peeking at, and my F1 fell to 0.41. The detector never changed; only my honesty did."
A Chastened Benchmark AI Agent
Prerequisites
This section stress-tests the detectors built in Section 38.3 and Section 38.4, so it assumes their residual-and-threshold machinery. The evasion half rests on gradient-based adversarial examples and sensor spoofing, developed in Chapter 68. The evaluation half is the anomaly-detection face of the leakage discipline in Chapter 5 and the leakage-safe benchmarking protocol of Chapter 65, and its honest-threshold fix borrows the distribution-free calibration of Chapter 18. We take the attack-versus-fault framing of Section 38.2 as given.
The Big Picture
Two very different failures wear the same disguise here, and both make a detector look far better on paper than it is on a plant. The first is an active adversary: an attacker who owns some sensors or actuators does not just launch an attack and hope, but shapes the attack so the detector stays quiet, exploiting the fact that a learned scorer has smooth, differentiable blind spots. The second is a self-inflicted failure of measurement: the evaluation protocol itself peeks at the test-time attacks when it normalizes the data or picks the alarm threshold, so the reported number describes a detector that could only exist if it knew the answers in advance. Chapter 5 warned about training on the future; this section is about the subtler cousin, leaking the answer key into the decision rule at test time, and about a defender who must survive both a clever attacker and an unforgiving, honest scoreboard. Get either wrong and you ship a monitor that a control room trusts and an adversary walks through.
Attacking the detector, not just the plant
A residual detector is a differentiable function from sensor window to anomaly score, and anything differentiable can be optimized against. Suppose an attacker wants to drive a tank level to a damaging value while keeping the detector's score \(s(\mathbf{x})\) below its alarm threshold \(\tau\). If the attacker can perturb a subset of readings by \(\boldsymbol{\delta}\) (the sensors or actuators they control), the evasion is a constrained optimization,
\[ \min_{\boldsymbol{\delta}} \; s(\mathbf{x} + \boldsymbol{\delta}) \quad \text{subject to} \quad g(\mathbf{x} + \boldsymbol{\delta}) \ge d,\; \lVert \boldsymbol{\delta} \rVert \le \epsilon, \]where \(g\) measures the physical damage the attacker wants (the tank actually over-fills) and \(\epsilon\) bounds how far the spoofed readings may stray before other checks catch them. This is a physics-constrained adversarial example: unlike an image attack, the perturbation must respect that the plant is a coupled dynamical system, so the attacker perturbs the exogenous inputs and lets the process equations carry the lie downstream. The reason this works is the same reason the detector works at all. A neural residual model is locally smooth, so its score has usable gradients that point straight into the region where the process is damaged yet the reconstruction still looks normal. Autoencoders are especially soft targets because their generalization, the property that lets them reconstruct unseen normal regimes, also lets a gently nudged attack ride through the bottleneck with a small residual.
Three defenses raise the cost. Adversarial training augments the normal-only training set with worst-case perturbations of healthy windows so the score surface steepens around the manifold boundary. Randomized smoothing adds calibrated noise and thresholds an averaged score, converting a sharp exploitable cliff into a certified margin the attacker must overcome. And, most robust of all in cyber-physical settings, non-differentiable redundancy: the hard physical invariants of Section 38.1 (mass balance, actuator-state consistency) have no gradient for the attacker to descend, so an evasion that fools the learned scorer still has to satisfy conservation laws it cannot smoothly optimize around. A detector that is only a smooth learned function is a detector with a documented escape route; pairing it with an invariant checker of a fundamentally different mathematical type is what closes it.
Key Insight
Robustness in ICS security is not a property of one model but of a heterogeneous ensemble. An attacker who can compute gradients can evade any single differentiable detector; what they cannot easily do is simultaneously satisfy a physical conservation law, keep a learned residual small, and stay inside the normal range of a rule-based limit alarm, because those three constraints have incompatible gradients (and one has no gradient at all). Diversity of detector type, not depth of any one detector, is the load-bearing defense. This is the anomaly-detection instance of the defense-in-depth principle developed for sensor spoofing in Chapter 68.
The transductive-leakage trap
Now the self-inflicted wound, and the one that has quietly corrupted much of the published ICS-detection literature. A detector is inductive when every decision rule it applies at test time (its normalization statistics, its threshold, its model) is fixed from training-and-validation data before it ever sees a test sample. It becomes transductive, and leaky, the moment any of those rules is computed using the test window itself, because the test window contains the very attacks it is supposed to detect blind. Three habits do this, each looking innocent:
Test-set normalization. Min-max or z-score scaling fit on the whole evaluation stream folds the mean and spread of the attack samples into the transform every clean sample is judged against, so the attack has already tinted the ruler. The oracle threshold. By far the most damaging, this is the near-universal habit of choosing the alarm threshold \(\tau\) that maximizes F1 on the test labels themselves, reported as "best-F1." No deployed monitor can do this, because it presumes you already know which samples are attacks; the number it produces is an upper bound achievable only by an operator holding the answer key. Point-adjust scoring, introduced in Section 38.3, is the trap's accomplice: it counts a whole anomaly segment as caught if any single sample fires, and combined with an oracle threshold it lets a detector emitting essentially random scores post near-perfect F1. The fix is a discipline, not a trick: split chronologically, fit every statistic and threshold on a clean validation prefix, and freeze them before touching the test set, exactly the inductive contract of Chapter 65. Where you want the false-alarm rate to be a number you chose rather than one you hope for, calibrate the threshold conformally on clean validation residuals (Chapter 18).
import numpy as np
from sklearn.metrics import f1_score
# scores from a mediocre detector; higher = more anomalous
# y_test marks the true attack samples (unknown at deploy time)
def best_f1_oracle(scores, y): # TRANSDUCTIVE: peeks at labels
taus = np.quantile(scores, np.linspace(0.5, 0.999, 200))
return max(f1_score(y, scores > t) for t in taus)
def inductive_f1(s_val, s_test, y_test, q=0.995): # honest: tau from clean val
tau = np.quantile(s_val, q) # fixed before seeing the test set
return f1_score(y_test, s_test > tau)
rng = np.random.default_rng(0)
s_val = rng.normal(0, 1, 5000) # clean validation
s_test = rng.normal(0, 1, 5000); y_test = np.zeros(5000, int)
atk = slice(2000, 2200); y_test[atk] = 1
s_test[atk] += rng.normal(0.6, 1, 200) # weak, barely-separable attack
print(f"oracle 'best-F1' = {best_f1_oracle(s_test, y_test):.2f}")
print(f"inductive F1 = {inductive_f1(s_val, s_test, y_test):.2f}")
best_f1_oracle sweeps the threshold against the true test labels and reports the maximum, which is the "best-F1" number pervasive in the literature; inductive_f1 fixes the threshold from a clean validation stream and never consults y_test. On a barely-separable attack the oracle figure can be double the honest one, and only the second is achievable by a monitor that does not already know the answers.Listing 38.3 makes the gap concrete and reproducible: swapping only the threshold-selection rule, with the identical detector and identical scores, moves the headline metric dramatically. When you read a paper reporting best-F1 with point-adjust, you are reading the oracle number, and the deployable performance is the lower, inductive one it usually omits.
Right Tool: an inductive, leakage-safe evaluation harness
Hand-writing chronological split logic, per-event detection accounting, delay curves, and both adjusted and un-adjusted metrics is 200-plus lines that are easy to get subtly wrong (and where a single stray fit on the test set reintroduces the leak). The TSB-AD / TimeEval evaluation suites provide a vetted harness:
from timeeval import TimeEval, DatasetManager, DefaultMetrics
# fits detectors, enforces a train/test boundary, and reports
# range-aware metrics WITHOUT the oracle point-adjust threshold
te = TimeEval(dm, algorithms, metrics=[DefaultMetrics.RANGE_PR_AUC])
te.run()
TimeEval, replacing roughly 200 lines of split, scoring, and metric code. The library owns the train/test boundary and threshold-free range metrics (VUS-PR, range-AUC) that sidestep the oracle-threshold trap entirely; you still own the chronological split definition and the choice to report an operationally fixed operating point alongside the threshold-free curve.
Reporting numbers a control room can trust
The escape from both traps is the same instinct applied twice: never let the thing you are trying to detect inform the rule that detects it, and never let a clever adversary find a smooth path your evaluation never probed. Concretely, adopt threshold-free metrics where you can (the area under the precision-recall curve, or its range-aware variants VUS-PR and range-AUC, which need no threshold and so cannot be gamed by an oracle one), and where an operating point is unavoidable, fix it inductively on clean validation and report the resulting false-alarm rate and median detection delay as first-class numbers. Then, separately, report robustness: the detection rate not on the recorded attacks but on adaptive ones synthesized against your specific model, because a detector's honest score against a static test set says nothing about its behavior against an adversary optimizing to evade it. A monitor that scores well on a chronological, inductive, threshold-free protocol and degrades gracefully under adaptive evasion is one whose reported numbers will survive the trip from the paper to the plant; anything validated with a peeked threshold and no adaptive attacker is a number about a world where the defender already knows the answer, a world in which no security matters. The distribution-shift companion of this story, why a detector honest today drifts into false alarms as the plant ages, is the province of Chapter 66.
In Practice: an autonomous-vehicle radar-spoofing bake-off
An automotive team benchmarks three anomaly detectors on logged radar and CAN-bus streams from a fleet, including a scripted spoofing campaign where a roadside emitter injects phantom returns. Their first internal report shows the deep reconstruction model winning at F1 0.94. A reviewer notices the threshold was tuned to maximize F1 against the labeled spoof windows and the features were min-max scaled over the full log. Re-run inductively, with scalers and threshold frozen on a clean pre-campaign drive and range-AUC as the headline, the deep model drops to 0.58 and now sits behind a lightweight physics-invariant checker (relative velocity must be consistent with wheel-speed odometry) that the spoof cannot satisfy. Worse, when the team synthesizes an adaptive spoof by descending the deep detector's score gradient, its detection rate collapses to near zero while the invariant checker is untouched, because the odometry constraint has no gradient to exploit. The shipped monitor becomes the ensemble: the learned model for coverage of subtle faults, the invariant for adversary-proof spoof rejection, evaluated only ever with a frozen threshold.
Research Frontier
The current reckoning is led by the TSB-AD benchmark (NeurIPS 2024) and the earlier TimeEval study, which re-evaluated dozens of time-series anomaly detectors under leakage-safe protocols and found that removing point-adjust and oracle thresholds erases most of the claimed advantage of deep models over simple baselines, in several cases inverting the ranking. On the attack side, work on adaptive and physics-constrained adversarial examples for ICS (extending the Carlini-Wagner and PGD families to state-space-constrained plants) shows learned detectors evaded with perturbations small enough to pass rule-based limit alarms, and certified defenses via randomized smoothing are only beginning to be adapted from image classifiers to multivariate control streams. The open frontier is a detector whose robustness is certified against a bounded physical adversary and whose reported accuracy is measured threshold-free, so that the paper number and the plant number finally coincide.
Exercise
Take any detector you built for Section 38.3 on a testbed such as SWaT or HAI. (1) Reproduce Listing 38.3 on your real scores: report best-F1 with the oracle threshold and the point-adjust protocol, then report the inductive F1 with a threshold frozen on a clean validation prefix and the threshold-free range-AUC. Tabulate all four and explain which one you would defend to an auditor. (2) If your detector is differentiable, synthesize an adaptive attack by taking a genuine attack window and running a few gradient steps to minimize its anomaly score under a small perturbation budget; report how far the detection rate falls. (3) Add one non-differentiable physical invariant from Section 38.1 and show it still flags the adaptive attack the learned model now misses.
Self-Check
1. What makes an evaluation "transductive," and name two concrete habits (one about normalization, one about thresholds) that leak the test-time attacks into the decision rule.
2. Why is a physical-invariant checker harder for a gradient-based adversary to evade than a neural residual model, and what does this imply about single-model versus heterogeneous-ensemble defenses?
3. Why does reporting range-AUC or VUS-PR sidestep the oracle-threshold trap, and when must you nonetheless also report a fixed operating point?
What's Next
In Section 38.7, we take the honestly-evaluated, adversary-hardened detector out of the lab and wire it into a security operation: routing its alarms into a SOC and SIEM, enriching them with the root-cause localization of Section 38.5, managing the alert-fatigue budget the false-alarm rate now makes explicit, and closing the loop from detection to human response and incident playbook.