Every attacker has a budget.
The academic literature on darknet exploit markets has been mapping this since at least 2017 β Robertson et al. built the formal model, and it held up well for its era. You had k_atk: the attacker's total budget. You had c_ex: the cost of a specific exploit. You had the defender's constraint set C: the things that cannot be patched because the business needs them running. The math suggested that if the defender could keep the wall expensive enough, the rational attacker would move to softer targets.
The model was correct. The variables evolved into something else.
The Fixed Price Tag Is Gone
In the 2017 model, c_ex was a market price. You went to a darknet forum, you bought GovRAT or a Flash zero-day, you knew what you paid. The exploit had a cost, you compared it to the expected payoff, you made a decision. Rational actor behavior under budget constraint. Predictable.
c_ex in 2026 is an inference cost.
Attackers are not buying exploit kits and deploying them. They are renting GPU time and running autonomous agents that perform thousands of micro-probes per second β probing response patterns, timing variations, error message differences, behavioral fingerprints. The exploit is not purchased; it is generated, customized to the specific target, specific version, specific configuration, in real time.
The Exploit Function that used to map tool-to-vulnerability is now a generative process. The attacker does not need to know your exact vulnerability in advance. They need compute and time. Your constraint set C β the legacy dependency that cannot be patched, the unrotated credential, the internet-facing service that should not be internet-facing β is no longer hidden behind friction. It is visible to any automated scanner that runs long enough.
The math still works. The attacker is still comparing k_atk to expected payoff. The cost structure changed: reconnaissance got cheap, customization got cheap, patience is no longer required because the agent runs while the attacker sleeps.
The Slow Poison: Skewing the Baseline
The overlap payoff in the original model was binary: attacker's tool hits defender's unpatched hole, attacker wins a point. Clean, measurable, gameable by either side.
The asymmetric payoff in 2026 is not a point. It is a baseline.
An attacker who understands your detection strategy does not need to find a clean path through. They need to find the noise floor of your monitoring β the level at which your SIEM or your AI-based EDR considers traffic normal β and then operate just below it. Not crashing through the wall. Slowly teaching the system that what they are doing is unremarkable.
The technique is model poisoning through behavioral normalization. Send gray traffic β activity that is individually ambiguous, collectively meaningful β over weeks or months. Your detection model updates on what it sees. The baseline of "normal" drifts. Behavior that would have triggered an alert at the start of the campaign no longer triggers one because the model has been taught, gradually, that this pattern is Tuesday.
# What detecting baseline drift looks like β not catching the attack,
# catching the slow movement of "normal" that precedes the attack
import numpy as np
from collections import deque
class BaselineDriftDetector:
def __init__(self, window_size=1000, drift_threshold=2.5):
self.window = deque(maxlen=window_size)
self.initial_mean = None
self.initial_std = None
self.drift_threshold = drift_threshold # standard deviations
def calibrate(self, initial_observations):
"""Establish baseline from clean historical data"""
self.window.extend(initial_observations)
self.initial_mean = np.mean(initial_observations)
self.initial_std = np.std(initial_observations)
def observe(self, value):
self.window.append(value)
current_mean = np.mean(self.window)
# How far has the current mean drifted from the calibrated baseline?
drift = abs(current_mean - self.initial_mean) / (self.initial_std + 1e-9)
if drift > self.drift_threshold:
return {
"alert": True,
"drift_score": drift,
"baseline_mean": self.initial_mean,
"current_mean": current_mean,
"message": f"Baseline drift detected: {drift:.2f}Ο from initial"
}
return {"alert": False, "drift_score": drift}
# Use it: feed your detection model's feature distributions through this
# If the "normal" traffic profile is slowly moving, someone is teaching it to move
detector = BaselineDriftDetector(window_size=500, drift_threshold=2.0)
The critical insight: the attack is not in the payload. The attack is in the slow movement of what your system considers normal. By the time the actual intrusion happens, the detection model has been coached to interpret it as background noise. The alert does not fire. The attacker who took three months to shift the baseline spends three minutes on the objective.
