ESC
> PressHaven alpha
Home › Docs ›Detection › Advanced Signals

Advanced Signals

Behavioural analysis, scoring and escalation-aware decay

Testability Pure decision modules Every rule returns data; nothing in the pure half performs I/O, so the behaviour is reproducible. plain Lua tests
AbuseIPDB Deterministic reporting Only whitelisted reasons may be reported, and the comment always names the matched CVEs. auditable gate
Fairness Escalation-aware decay Repeat offenders fade more slowly; a permaflag stops decay once the session has earned it. 4 parameters

Vulnerability Pattern Detection (vulnerability_rules.lua)

Responsible for direct pattern matching against URI requests to identify known vulnerability patterns or exploit kit signatures. Uses lua_pattern_utils.escape_pattern for safe pattern matching. The core function detect_vulnerability_pattern(uri, args, wcpay_checkout_user_header) analyzes request URIs to flag potential vulnerabilities.

Threat Alert Processing (suricata_rules.lua)

Turns eve.json alerts into per-IP reputation scores and reason strings, which feed routing stage 6 ("IP reputation"). Its functions are listed on Suricata Network IDS; its decay is the shared policy below.

Behavioural & Sophistication Signals

Beyond matching a single request, sophistication_analyzer.lua classifies a whole session as scripted, ai_assisted, manual or unknown using an inspectable weighted rule set. Every contributing signal is returned in a signals list, and the confidence is simply the winning class's share of the total weight — so the classification is auditable, not a black box.

SignalWhat it readsLeans toward
TimingMean and standard deviation of inter-request gaps across the session.Very regular, fast cadence → scripted; human-like variance → manual; in between → ai_assisted.
User-agentKnown scanner fragments, SDK/agent markers, or a normal browser string.Scanner UA → scripted (+35); agent/SDK marker → ai_assisted (+35); browser UA → manual.
HeadersPresence of browser-like headers such as Accept-Language.Present → manual (+20); absent → split evenly between scripted and ai_assisted (the UA/timing signals disambiguate).
PrecisionHow noisy vs targeted the matched patterns are.Broad, noisy "spray" → scripted (+20); few precise high-value matches → ai_assisted / manual.

Two further high-confidence signals feed the same picture:

  • Honeytokens — a later request carrying one of the five injected fake credentials (API key, DB creds, admin password, S3 URL, JWT secret) confirms compromise. See Detection Capabilities.
  • Device signature — the consent-gated, one-way GDPR signature re-recognises a returning adversary after a cookie and storage wipe, so a reset session does not launder prior risk.

AbuseIPDB Reporting Logic (abuseipdb_rules.lua)

Governs the deterministic decision-making process for reporting detected IP addresses to the AbuseIPDB service. Acts as a whitelist for reportability.

  • Category Mapping: Maintains _M.REASON_CATEGORIES mapping routing reasons to AbuseIPDB category IDs.
  • Reportability Check: _M.is_reportable_reason(reason) checks if a reason is in the whitelist.
  • Comment Generation: Constructs detailed report comment, including associated CVEs.

Risk Scoring Model

Per-signal score deltas are listed once, by analyser stage, in Detection → Detection Stages. Static assets are always skipped (0), the accumulated score is capped at 100, and a session is diverted at the honeypot threshold of 80 (honeypot_threshold; see the Configuration Reference).

Escalation-Aware Decay (decay_policy.lua)

Shared by two risk-score decay paths: router_rules.decayed_score() (per-session) and suricata_rules.decayed_score() (per-IP reputation).

  • The half-life multiplier grows linearly with offenses: 1 + decay_offense_slowdown × offenses, so repeat offenders fade progressively more slowly.
  • Past permaflag_offenses offenses, OR once the stored peak has ever reached permaflag_score, decay stops entirely (permaflag).
  • Default: decay_offense_slowdown = 0.75, permaflag_offenses = 5, permaflag_score = 100.

The core of decay_policy.lua:

function _M.half_life_multiplier(offenses, slowdown)
    offenses = tonumber(offenses) or 0
    slowdown = tonumber(slowdown) or 0
    if offenses <= 0 or slowdown <= 0 then return 1 end
    return 1 + slowdown * offenses
end

-- in decay(), after the peak <= 0, no-elapsed-time and permaflag early returns:
local eff_half_life = base_half_life * _M.half_life_multiplier(offenses, cfg.decay_offense_slowdown)
return peak * (0.5 ^ (elapsed / eff_half_life))

With the defaults, a session with two prior offenses decays with a 2.5× longer half-life (750 s instead of 300 s).

Measured vs configured half-life

The configured half-life is 300 s, but a recorded exploit test-scenario run measured the effective half-life at 529 s (95% CI 475–596 s, exponential fit R² = 0.99) — well outside the configured value. That is the escalation-aware slowdown working as designed: each prior offense adds linearly to the half-life multiplier, so a session that has already misbehaved fades more slowly than the base constant suggests. The decay the router applies is the curve the measurement tracks, not the raw 300 s.

Relevance: Ensures that only high-confidence, logic-driven signals (combining CVEs, Suricata alerts, and IP reputation hits) lead to external reporting.