✓ Human-authored analysis; AI used for formatting and proofreading.
Stave is a cloud configuration verifier. It analyzes AWS configuration snapshots against a catalog of controls and compound attack chains. It finds things that single-resource scanners miss, including compound findings where individually low-severity configurations combine into critical attack paths.
It also gets things wrong. Not occasionally or accidentally, but structurally. There are categories of security problems that Stave cannot detect. Because the approach has boundaries that no engineering effort can remove. Understanding those boundaries matters more than understanding the capabilities, because a tool you trust beyond its boundaries is worse than no tool at all.
Here are seven things Stave gets wrong, why it gets them wrong, and what to use instead for each one.
1. Stave cannot see what the collector doesn't capture
Stave evaluates a snapshot. The snapshot is produced by a collector that calls AWS APIs and records the responses. If the collector doesn't call the API for a specific service, that service doesn't exist in the snapshot. If the service doesn't exist in the snapshot, no control can evaluate it. The control doesn't fail — it silently doesn't fire.
This is not a hypothetical concern. In July 2026, we discovered that three S3 sub-features — S3 Express (Directory Buckets), S3 Tables, and S3 Vectors — use separate IAM action namespaces (s3express:, s3tables:, s3vectors:) from the main s3: namespace. All 148 S3 controls in the catalog evaluate only the s3: namespace. Directory Buckets, Table Buckets, and Vector Buckets are invisible. They have their own bucket policies, their own access controls, and their own public-exposure surface. None of it is checked.
We found this through a HAZOP audit — applying systematic deviation analysis to the gap-finding process itself — not through a customer report or an incident. It had been invisible since those features launched.
AWS ships roughly a hundred features per month. Each one potentially introduces new resource types, new policy mechanisms, new IAM action namespaces. The collector lags behind these launches. The control catalog lags behind the collector. At any given time, there are AWS services and features that exist in your environment and have no corresponding controls. We track coverage and publish it, but the gap is structural. It exists at every moment, for every verifier, and it will never be zero.
What to use instead: For services Stave doesn't cover, the stave readiness command reports which asset types are missing from the snapshot and which controls are blocked. Treat a readiness report showing zero observations for a service you use as a finding, not as silence.
2. Stave cannot see application-layer vulnerabilities
The Capital One breach required three conditions: an EC2 instance with IMDSv1 enabled, a public IP, and an overpermissioned IAM role. Stave catches all three. But the breach also required a fourth condition: a server-side request forgery vulnerability in the WAF application running on that instance. Stave cannot see that.
Stave verifies configuration. It does not analyze source code, runtime behavior, application logic, or software vulnerabilities. The SSRF that initiated the Capital One attack is invisible to any configuration verifier. It lives in the application, not in the AWS configuration. The same is true for SQL injection, command injection, authentication bypass, deserialization vulnerabilities, and every other class of code-level flaw.
This means every Stave finding has an implicit caveat: "this configuration enables exploitation IF an attacker has an entry point." The compound finding tells you the configuration prerequisites for a named attack pattern are satisfied. It does not tell you whether the application-layer entry point exists. A Capital One chain finding on an instance running a hardened application with no SSRF vulnerability is a true positive (the configuration is wrong) and simultaneously a lower operational priority (the entry point doesn't exist today).
What to use instead: Application security testing — DAST, SAST, SCA — for the application-layer entry point. Stave tells you the blast radius if an entry point exists. Application testing tells you whether one does. Both answers are needed; neither is sufficient alone.
3. Stave reports what is possible, not what is happening
A security group rule allowing inbound 0.0.0.0/0 on port 3389 is a Stave finding. It does not mean anyone is connecting via RDP. An IAM role with AdministratorAccess is a Stave finding. It does not mean anyone is using that role. A public S3 bucket is a Stave finding. It does not mean anyone has accessed it.
Stave evaluates configuration state — what the infrastructure permits. It does not evaluate runtime state — what is actually occurring. The gap between "permitted" and "happening" can be large. An overpermissioned role that hasn't been assumed in two years is a real misconfiguration and a real cleanup candidate, but it's not an active threat in the same way that a role being assumed from an unexpected IP address.
This is a structural limitation of static analysis. Stave sees the security group rule. It doesn't see the network flow. It sees the IAM policy. It doesn't see the CloudTrail event. It sees the S3 bucket policy. It doesn't see the access log.
What to use instead: Runtime monitoring — CloudTrail analysis, VPC Flow Logs, GuardDuty, SIEM — for what is happening. Stave's finding says "this could be exploited." Runtime monitoring says "this is being exploited." The configuration finding should trigger a review; the runtime finding should trigger an incident.
4. Stave sees one moment, not the timeline
A snapshot is a point-in-time capture. Stave evaluates what was true when the snapshot was taken. It does not know what was true five minutes before or what will be true five minutes after.
This matters in two specific ways. First, a misconfiguration that existed between two snapshots is invisible. If a developer opens a security group at 10am, deploys, and closes it at 10:15am, and the snapshot runs at 11am, Stave never sees the exposure. Second, a TOCTOU (time-of-check-time-of-use) race condition can make a snapshot misleading. The payer invariant enforcer — an EventBridge rule that triggers a Lambda to apply permission boundaries to new IAM principals — has a window between principal creation and boundary application. A snapshot taken after enforcement shows the boundary in place. The window during which the principal was unprotected is invisible.
Continuous snapshot evaluation reduces but does not eliminate this gap. An hourly snapshot catches a configuration that was wrong for an hour; a configuration that was wrong for five minutes during the hour between snapshots is still invisible.
What to use instead: Event-driven detection — CloudTrail event triggers, EventBridge rules, AWS Config rules with change-triggered evaluation — for changes that happen between snapshots. Stave's periodic evaluation catches persistent misconfigurations. Event-driven detection catches transient ones.
5. Stave cannot help when the provider fails
In July 2023, a Microsoft signing key was compromised (Storm-0558). In July 2024, a CrowdStrike content update crashed 8.5 million Windows machines. In May 2024, Google Cloud accidentally deleted a UniSuper customer's entire environment. In none of these cases was there a customer-side configuration invariant that would have detected or prevented the failure. The threat actor was the provider.
Stave verifies what you control. When the provider is the threat, when the signing key that authenticates your identity tokens is compromised at the provider level, when the security agent you're required to install pushes a bad update, when the cloud provider's control plane deletes your data — there is no configuration in your snapshot to check. The invariant surface is empty.
This is not a limitation of Stave specifically. It's a limitation of any tool that operates within the trust boundary of the platform. If you trust AWS to run the control plane correctly, and AWS runs it incorrectly, no tool running on top of that control plane can detect the failure. The failure is below the verification layer.
What to use instead: Multi-provider resilience architecture, vendor risk assessment, contractual SLAs, and incident response planning. These are organizational and contractual controls, not technical ones. No configuration verifier — ours or anyone else's can verify the provider's internal operations.
6. Stave's thresholds are opinions, not invariants
The blast radius control fires when a role reaches more than 20 sensitive resources. Why 20? Not 15, not 30? The stale credential control fires at 90 days. Why not 60, why not 120? The long-running instance control uses 365 days. The orphaned EBS volume control uses 30 days.
Every threshold in the catalog is an engineering judgment, not a derived property. We chose numbers that balance signal against noise for a typical organization. They are defaults, not truths. An organization with 10 S3 buckets and a role reaching 8 of them has a role reaching 80% of its data — arguably more dangerous than a role reaching 20 out of 2,000 buckets in a large organization. The absolute number is the same in neither case; the blast radius relative to the data surface is very different.
Some controls avoid thresholds entirely. A public S3 bucket is a finding regardless of how many objects it contains, because the invariant is binary (public or not public). These are the strongest controls in the catalog because they don't depend on judgment. The threshold-based controls are weaker precisely because the threshold is an opinion.
What to use instead: Override the defaults. Stave's threshold-based controls are configurable. An organization that treats 5 sensitive resources as the blast radius boundary for a development account and 50 for a production account is applying better judgment than the default. The defaults should be a starting point, not an end state.
7. Missing data looks like safety
This is the most dangerous limitation. When a control's predicate references a field that doesn't exist in the observation. Because the collector didn't capture it, the AWS API doesn't return it, or the resource type is too new — the predicate evaluates against a null value. In most expression languages, including CEL, a comparison against null fails. If the predicate is structured as "fire when field X is true," and field X is absent, the predicate doesn't fire. The control passes. The resource appears safe.
It's not safe. The data to determine whether it's safe was never collected. The pass is vacuous. It tells you nothing, but it looks identical to a genuine pass in every report, every dashboard, and every compliance export.
We built the SILENT_RISK classification to address this: controls that pass because required fields are missing are classified separately from controls that pass because the resource is genuinely safe. The implicit_dependencies schema extends this to compound findings. Each chain declares what upstream computations it depends on and what happens when they haven't run. But these are mitigations, not solutions. At the boundary of what the snapshot contains, every verifier faces the same problem: absence of evidence is not evidence of absence, but every report format treats them identically.
What to use instead: Run stave coverage and read the SILENT_RISK count as carefully as you read the violation count. A report that shows 200 violations and 50 SILENT_RISK findings has 50 controls where the answer is "we don't know," not "we're safe." Treat SILENT_RISK as a finding class, not as background noise.
What this means for how to use Stave
A configuration verifier is one layer in a security architecture, not a replacement for one. The seven limitations above define the boundaries of that layer:
Stave tells you what your configuration permits. It does not tell you what your applications contain, what your users are doing, what your provider is doing internally, what happened between snapshots, or what will happen when the next AWS feature launches. It does not tell you that 20 is the right threshold for your organization or that a passing control on a service it has never collected is meaningful.
What it does tell you — deterministically, reproducibly, from a snapshot you already have is whether the configuration prerequisites for named attack patterns exist in your environment, and how many of those patterns are one control change away from activating. That's a specific, bounded claim. Trust it within its boundaries. Use something else outside them.
A tool that claims to catch everything is the tool you cannot trust. Every tool has boundaries. The ones that name them are the ones worth using.
Top comments (0)