Documentation Index
Fetch the complete documentation index at: https://quintsecurity.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Divergence Detector
The divergence detector is a dedicated cloud service that joins agent intent events from the forward proxy with OS truth events from Endpoint Security and the Network Extension. It produces the detections that prove Intent vs Truth correlation works at runtime: prompt injection, tool spoofing, data exfiltration, and credential theft that single-stream products cannot observe.
Why a dedicated service
Intent and truth events arrive through the same ingestion pipeline but originate from different collectors on the edge. The forward proxy emits intent events derived from parsed LLM API responses. The Endpoint Security extension and Network Extension emit truth events derived from kernel syscalls and network flows. Both streams carry the same session identifier because the unified session tracker on the daemon attributes them to the same root process.
Correlation requires a time-windowed join across the two streams, keyed by session, with per-session state that persists across event arrivals. The pipeline writer does not fit this shape — its job is to persist events to Postgres as they arrive, one at a time, with strict idempotency. A stream processor with windowed state is a different computation model.
The divergence detector runs as its own ECS Fargate service consuming from a dedicated SQS queue subscribed to the same SNS topic as the pipeline writer. It maintains per-session state in Redis with short TTLs, runs the correlation algorithm as events arrive, and writes detection rows back to Postgres through the same row-level security enforcement the rest of the platform uses.
The data model
Canonical intent event
Derived from AgentToolEvent emitted by the daemon’s OnToolCall callback after the forward proxy’s LLM parser extracts tool_use blocks from response bodies.
| Field | Type | Description |
|---|
event_id | UUID | Unique event identifier |
session_id | UUID | Unified session ID from the daemon |
timestamp | timestamptz | Proxy intercept time |
tool_name | text | Agent-reported tool name (e.g., Bash, Read, Edit) |
claimed_action | text | Normalized action type (see taxonomy below) |
claimed_target | text | Extracted path, URL, or resource identifier |
provider | text | LLM provider (anthropic, openai, bedrock, etc.) |
model | text | Specific model identifier |
platform | text | Agent platform (claude-code, cursor, copilot) |
process_pid | integer | PID of the agent process |
Canonical truth event
Derived from ESEvent, NEFlowEvent, and NEFilterFlowEvent events normalized through the daemon’s adapter layer.
| Field | Type | Description |
|---|
event_id | UUID | Unique event identifier |
session_id | UUID | Unified session ID from the daemon |
timestamp | timestamptz | Kernel-observed time |
observed_action | text | Normalized action type |
observed_target | text | File path, host, or binary path |
observed_process | text | Process binary path |
pid_chain | integer[] | Root PID through parent to observed PID |
source | text | es, ne, or ne_filter |
Action taxonomy
Both streams normalize into a shared action_type enum before comparison. A representative subset:
| Raw input | Canonical type | Canonical target |
|---|
Bash("command") | BASH_EXECUTION | first token of command |
Read({"file_path": X}) | FILE_READ | X |
Write({"file_path": X}) | FILE_WRITE | X |
Edit({"file_path": X}) | FILE_WRITE | X |
WebFetch({"url": X}) | HTTP_REQUEST | URL host |
ES AUTH_EXEC | PROCESS_EXEC | executable path |
ES NOTIFY_WRITE | FILE_WRITE | file path |
NE outbound_flow | NET_CONNECT | host:port |
For shell commands, the detector additionally extracts primary actions — a Bash tool call running curl ... | sh produces both a BASH_EXECUTION intent and derived HTTP_REQUEST plus BASH_EXECUTION intents for the piped components.
The correlation algorithm
Time-window join
The detector maintains a per-session ring buffer of recent events, partitioned by source (intent vs truth) and sorted by timestamp. Buffer TTL is 30 seconds; older events are evicted. For each arriving event, the detector scans the opposite-source buffer within a configurable time window (default ±5 seconds) for compatible matches.
A match requires:
- Same session identifier
- Timestamps within the window
- Compatible action types (e.g.,
BASH_EXECUTION intent can match PROCESS_EXEC truth if the process argument matches the command string)
- Target resource compatibility (exact match or prefix match for file paths, same host for network targets)
Matched events are marked correlated and emit no divergence.
Orphan detection
Events that remain unmatched after the window expires are orphans. An intent orphan (no matching truth) triggers a PHANTOM_INTENT detection. A truth orphan (no matching intent) triggers a SHADOW_ACTION detection. Both emit to the divergence_events table and, for high-confidence cases, to threat_detections.
The six divergence shapes
See Intent vs Truth for the full taxonomy. Each divergence type has:
- A detection rule (how the correlation miss is recognized)
- A false-positive mitigation (known-noise filters)
- A severity classification (INFO, MEDIUM, HIGH, CRITICAL)
- A product action (log, alert, or block depending on enforcement mode)
Confidence scoring
Not every correlation miss is an attack. The detector assigns a confidence score to each divergence based on accumulated evidence:
| Factor | Weight |
|---|
| Session age (older sessions have less noisy baselines) | +0.1 per hour up to +0.3 |
| Known-good pattern match (cron job, npm postinstall, language server) | −0.5 |
| Multiple mismatches aggregated in the same session | +0.2 per additional |
| Process tree match (same PID chain) | +0.2 |
| Target IP is a known provider (Anthropic, OpenAI, GitHub) | −0.4 |
Detections below 0.6 confidence are logged but do not page. Detections above 0.9 can trigger blocking in strict enforcement mode. The confidence thresholds are tuned per customer from analyst feedback in the dashboard.
Schema
The detector writes to two Postgres tables, both with row-level security enforced.
CREATE TABLE divergence_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
org_id UUID NOT NULL,
session_id UUID NOT NULL,
detection_type TEXT NOT NULL CHECK (detection_type IN (
'phantom_intent',
'shadow_action',
'target_mismatch',
'scale_mismatch',
'timing_mismatch',
'truth_precedes_intent'
)),
event_id UUID NOT NULL,
event_source TEXT NOT NULL,
event_type TEXT NOT NULL,
resource_claim TEXT,
window_start TIMESTAMPTZ NOT NULL,
window_end TIMESTAMPTZ NOT NULL,
candidates INT DEFAULT 0,
confidence FLOAT NOT NULL,
detection_id UUID REFERENCES threat_detections(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
ALTER TABLE divergence_events ENABLE ROW LEVEL SECURITY;
ALTER TABLE divergence_events FORCE ROW LEVEL SECURITY;
CREATE POLICY div_org_isolation ON divergence_events
USING (org_id::text = current_setting('app.current_org_id', true));
Failure modes
Clock skew
Intent and truth timestamps both originate from the same daemon process using the kernel monotonic clock. Cross-stream skew within a session is measured in microseconds and is not a practical concern. Cross-machine skew is irrelevant because correlation never happens across machines — Quint correlates within a single session on a single host.
Missing ES events
When the Endpoint Security extension crashes or is temporarily unavailable, heartbeat events stop. The detector subscribes to heartbeats and, during gaps, suppresses PHANTOM_INTENT detections for sessions on the affected host. SHADOW_ACTION detections continue to fire normally during such gaps — something running that should not be is a stronger signal than something declared that did not happen.
Missing proxy events
The forward proxy can drop intent events if the SSE stream is truncated mid-response, if the request body exceeds the parser’s size limit, or if the parser encounters malformed input. A PROXY_PARSE_FAILURE marker event is forwarded to the cloud when this happens. The detector recognizes markers and reduces confidence on TRUTH_WITHOUT_INTENT detections for affected sessions, because the absence of intent may reflect parser failure rather than attack.
Adversarial evasion
A sophisticated attacker aware of Quint’s architecture might attempt to race the correlation window, spoof intent events, or delay execution beyond the window. The detector’s mitigations:
- Race attempts: Target compatibility is checked, not just timing. A file write to
/etc/passwd will not match an intent for /app/config.yml regardless of window alignment.
- Intent spoofing: Requires compromising the LLM provider’s TLS, the daemon’s forward proxy, or the model’s response content. At that point the attacker can also disable the detector itself; the threat model is beyond runtime correlation.
- Delayed execution: Actions that execute minutes or hours after the intent fall outside the correlation window by design. These are caught by separate behavioral analytics at the session level, not by the real-time divergence detector.