In 2019, a former AWS employee exploited a server-side request forgery (SSRF) vulnerability in Capital One's web application firewall. The breach exposed over 100 million customer records.
But here's the thing security scanners missed: no single misconfiguration caused the breach.
It was the correlation of three weak signals that produced a critical finding:
- An SSRF vulnerability in the WAF configuration
- An overly permissive IAM role attached to the compromised instance
- Unencrypted S3 buckets containing sensitive customer data
Each finding alone? Low to medium severity. Together? A $190 million breach.
The Problem with Flat Scanners
Most cloud security tools evaluate configurations in isolation. They produce a flat list of findings:
WARN S3 bucket has public access enabled
WARN IAM role has overly broad permissions
INFO Server-side encryption not enabled
Three warnings. No critical alert. The tool did its job — it found each misconfiguration. But it missed the compound risk because it never correlated the signals.
This is the fundamental gap: a scanner that evaluates one configuration at a time cannot reason about the interaction between configurations.
Introducing Stave
Stave is an offline configuration safety evaluator. It takes two inputs — security controls written in YAML and observation snapshots of your cloud infrastructure — and produces a deterministic security assessment. No agents, no API keys, no network access required. It runs entirely on local data, which makes it suitable for air-gapped environments and audit-sensitive workflows.
The examples below use Stave's control language to illustrate how compound predicate evaluation closes the signal correlation gap.
Signal Correlation: The Missing Primitive
What security teams actually need is a way to express compound conditions — predicates that fire only when multiple weak signals appear together on the same asset:
id: CTL.S3.EXPOSURE.COMPOUND.001
name: Unencrypted Public Bucket with Broad IAM Access
description: >
S3 bucket is publicly accessible, lacks encryption, and is
accessible by an overly permissive IAM role. This combination
creates a high-severity data exfiltration risk.
severity: critical
unsafe_predicate:
all:
- field: public_access
op: eq
value: true
- field: server_side_encryption
op: eq
value: false
- field: iam_role_scope
op: eq
value: "overly_permissive"
The all combinator is the key. This control only fires when every condition is true simultaneously. Three medium-severity signals become one critical finding because the predicate explicitly models the compound risk.
How Compound Predicates Work
The evaluation model supports two combinators:
all — Every condition must be true (logical AND). Use this for compound risk scenarios where the danger comes from the intersection of weak signals.
any — At least one condition must be true (logical OR). Use this for detection breadth where multiple indicators point to the same root cause.
These nest arbitrarily:
unsafe_predicate:
all:
- field: public_access
op: eq
value: true
- any:
- field: server_side_encryption
op: eq
value: false
- field: kms_key_id
op: missing
This reads: "The bucket is publicly accessible AND (encryption is disabled OR no KMS key is configured)." Two different paths to the same compound risk.
Adding Time as a Correlation Axis
Here's where it gets interesting. A misconfiguration that appeared 2 hours ago is different from one that's been open for 90 days.
If your evaluation engine tracks when a configuration became unsafe — not just whether it's unsafe — you gain a temporal correlation axis:
Finding: CTL.S3.PUBLIC.001
Asset: patient-records-bucket
First unsafe: 2026-01-01T00:00:00Z
Duration: 2160 hours (90 days)
SLA threshold: 168 hours (7 days)
Status: NON_COMPLIANT
The same public_access: true finding has radically different severity depending on duration. A bucket that went public 2 hours ago during a deploy is an incident. A bucket that's been public for 90 days is a governance failure.
This requires observation snapshots — point-in-time captures of configuration state. With at least two snapshots, you can compute:
- When the unsafe state first appeared
- How long it has persisted
- Whether it's a new regression or a chronic drift
- Whether it exceeds the team's SLA threshold
The Three Correlation Dimensions
Putting it together, configuration risk is a function of three dimensions:
| Dimension | Question | Signal |
|---|---|---|
| Predicate | What combination of fields is unsafe? | Compound all/any conditions |
| Temporal | How long has it been unsafe? | Duration vs SLA threshold |
| Contextual | What else is true about this asset? | Cross-field correlation |
A flat scanner only covers the first dimension — and only one field at a time. Adding predicate composition catches Capital One-style compound risks. Adding temporal tracking catches chronic drift that compliance teams care about.
What This Looks Like in Practice
Given two observation snapshots of an S3 bucket captured a week apart, and a set of controls with compound predicates, the evaluation produces:
{
"kind": "ASSESSMENT",
"summary": {
"total_assets": 1,
"violations": 3
},
"status": "NON_COMPLIANT",
"findings": [
{
"control_id": "CTL.S3.PUBLIC.001",
"asset_id": "patient-records-bucket",
"evidence": {
"first_unsafe_at": "2026-01-01T00:00:00Z",
"unsafe_duration_hours": 336,
"threshold_hours": 168,
"temporal_risk": "SLA_EXCEEDED"
}
}
]
}
The output is machine-readable JSON. Teams pipe it into their SIEM, Splunk, or ticketing system. The evidence block provides the temporal proof that auditors need — not just "this is misconfigured" but "this has been misconfigured for 336 hours, exceeding your 168-hour SLA."
The Remediation Attestation
After fixing the findings, teams need proof that the fix worked. A before/after comparison produces an attestation:
{
"kind": "ATTESTATION",
"summary": {
"previous_violations": 3,
"current_violations": 0,
"remediated": 3,
"open": 0,
"regressions": 0
}
}
Zero regressions. Three remediated. This is the artifact that goes into the compliance record — formal proof that the compound risk was identified and resolved.
Building This Into Your Security Pipeline
The design decisions:
Controls are data, not code. Express compound predicates in YAML/JSON, not in Go/Python functions. This lets security teams author and review controls without touching the evaluation engine.
Observations are snapshots, not streams. Capture configuration state at discrete points in time. Two snapshots a week is enough for SLA tracking. This works offline and doesn't require agent installation.
The evaluation engine is deterministic. Given the same controls, observations, and timestamp, the output is byte-identical. This matters for audit reproducibility.
Separate the assessment from the remediation. The engine produces findings. A separate step verifies the fix. These are different artifacts with different schemas because they answer different questions.
Conclusion
The Capital One breach wasn't caused by one misconfiguration. It was caused by the correlation of three. Most security tools would have flagged each one individually. None would have flagged the compound risk.
If your configuration evaluation can express all/any predicate composition, track temporal duration against SLA thresholds, and produce machine-readable evidence — you're not just scanning. You're doing security assessment.
The difference matters when the auditor asks: "How long was this configuration unsafe, and what else was true at the same time?"
This article describes the evaluation model behind Stave, an offline configuration safety evaluator that uses compound predicate composition and temporal tracking to produce security assessments and remediation attestations.
Top comments (0)