Runtime Application Self-Protection (RASP)¶
The last line of defence once input filters and guardrails are bypassed: the
application watches its own behaviour for an attack already in progress — a
request-rate spike, an oversized payload, a halt-rate surge. RASP scores each
observation against a rolling baseline and reports an ok / watch / alert
verdict; the host decides whether to shed load, throttle, or block.
The detector is dependency-free and distribution-free: a streaming robust z-score (median + median-absolute-deviation), so a few extreme values — the attack itself — do not inflate the baseline and mask the next anomaly. (An IsolationForest ensemble can be layered on later; the robust statistic is the always-available floor.)
Quick start¶
from director_ai import ProductionGuard
from director_ai.core.config import DirectorConfig
rasp = ProductionGuard(DirectorConfig()).rasp
# Feed per-request behavioural metrics as they happen.
for rate in normal_request_rates:
rasp.observe("request_rate", rate) # builds the baseline
verdict = rasp.observe("request_rate", 5000) # a sudden flood
print(verdict.severity) # "alert"
print(verdict.to_dict()) # metric, value, robust_z, severity, anomalous, cold_start
if rasp.under_attack(min_anomalies=3):
... # shed load / escalate
Scoring and severity¶
observe(metric, value) returns an AnomalyVerdict:
| Field | Meaning |
|---|---|
metric |
The metric name. |
value |
The observed value. |
robust_z |
Median/MAD robust z-score against the rolling baseline. |
severity |
ok, watch, or alert. |
anomalous |
True when robust_z exceeds the threshold (default 3.5). |
cold_start |
True while the baseline is still filling (under min_samples). |
Severity bands: alert once robust_z crosses the threshold, watch once it
enters the shoulder below it (watch_fraction, default 0.7), ok otherwise. A
cold-start observation is always ok — there is no baseline to judge against yet.
When the MAD is zero but the window has spread (its known weakness, when over half the values equal the median), the detector falls back to the mean absolute deviation so an in-range value is not flagged as an infinite outlier; only a genuinely constant baseline scores any deviation as maximal.
State¶
observe()keeps a separateStreamingRobustDetectorper metric, each with its own rolling window — request rate, payload size, and halt rate are judged independently.recent_anomaly_countis the number of anomalies in the recent window;under_attack(min_anomalies=3)is the convenience threshold over it.tracked_metricslists the metrics with an active baseline.
All serialisation is tenant-safe — metric names and scores only, never request content. RASP scores; the host owns the block decision (for action-level gating, compose it with the execution rings).