Free plan Signups are open now. The full audytx engine — Terraform and CloudFormation — is live. The Free plan is 100 scans a month and stays free — paid tiers arrive Nov 01, 2026 from $20/month for unlimited repositories. Try it on your own code.
False positives · context-aware scanning

False positives, reasoned away in the open

A check that looks at one resource on its own can't see the context that makes it irrelevant, so clean infrastructure can light up with findings — a Lambda flagged for a missing dead-letter queue even when nothing async ever invokes it. audytx maps how your resources actually connect and keeps only what context can't explain away — every finding it sets aside stays visible with its reason, never dropped silently.

Measured

The numbers

audytx's own audited results. Method, samples and dates are on the benchmark page.

96.9%
audited precision on kept findings
engine 1.12.2 · July 2026 · 100-item sample
97.4%
of set-aside findings audited as correct
engine 1.12.2 · July 2026 · 40-item sample
20+
cross-resource reasoning axes
pre-computed once per scan
The root cause

Where false positives come from

A check that looks at one resource on its own has to fire whenever it could apply — it can't see the context that makes the check irrelevant. Five patterns audytx sets aside, and the noise a single-resource check emits instead.

1. Lambda DLQ pattern

The check: "Lambda function has no dead-letter queue"
A single-resource check: aws_lambda_function.api — Lambda DLQ missing ⚠
audytx: suppressed — this Lambda is only invoked synchronously via API Gateway. A DLQ only fires on async invocations; there are none here.

2. DLQ-needs-a-DLQ pattern

The check: "SQS queue has no dead-letter queue"
A single-resource check: aws_sqs_queue.jobs_dlq — Queue has no DLQ of its own ⚠
audytx: suppressed — this queue is the dead-letter target of aws_sqs_queue.jobs. Requiring a DLQ to have its own DLQ is infinite regress.

3. Ephemeral data pattern

The check: "DynamoDB table does not have point-in-time recovery enabled"
A single-resource check: aws_dynamodb_table.sessions — PITR not enabled ⚠
audytx: suppressed — TTL is configured on this table; the data is intentionally ephemeral. Point-in-time recovery is mismatched for data that self-expires.

4. Internal-load-balancer pattern

The check: "Load balancer does not have deletion protection enabled"
A single-resource check: aws_lb.internal_admin — Deletion protection disabled ⚠
audytx: suppressed — this is an internal load balancer with no internet route. Deletion protection matters most for public-facing LBs; internal-only LBs carry lower risk.

5. IMDSv2 inheritance pattern

The check: "EC2 instance does not enforce IMDSv2"
A single-resource check: aws_instance.worker — IMDSv2 not enforced ⚠
audytx: suppressed — IMDSv2 is enforced at the account level; this instance inherits that setting. No per-instance override is needed.
What it looks at

The reasoning checks

Each check is a kind of relationship between resources that can show a finding does not apply.

Queue is already a dead-letter target
A dead-letter queue does not need a dead-letter queue of its own.
Lambda is invoked synchronously
A function-level dead-letter queue only helps asynchronous invocations.
Data is intentionally short-lived
Data that expires on its own does not need point-in-time recovery.
Resource has no internet exposure
Findings aimed at public-facing resources can be set aside on internal-only ones.
Encryption method meets the check’s intent
A managed encryption key can satisfy an at-rest encryption check.
Role’s trust is narrowly scoped
A role that only a tightly scoped service can assume is treated as lower risk.
Role’s permissions are checked as granted
Some IAM findings are set aside when the role holds no dangerous grants.
Instance inherits an enforced setting
A metadata setting enforced at the launch-template or account level counts for the instance.
Failures are handled at the event source
When the event source owns failure handling, a function-level dead-letter queue is redundant.
Secret is automatically rotated
A secret rotated by a separate rotation resource counts as rotated.
The resource is switched off
A resource with count = 0 is never created, so findings on it are set aside.
An org policy already denies it
An attached organization policy that denies the action settles the finding above the resource.
The secret is a CloudFormation dynamic reference
A value read from Secrets Manager or an encrypted SSM parameter is not an embedded secret.
It’s CDK’s own bootstrap scaffolding
Resources CDK creates for its own tooling are not application infrastructure.
The stream’s source is already encrypted
A Firehose delivery stream fed from a Kinesis data stream or an MSK cluster is not asked for its own encryption setting.
The value is wired through a module output
A value passed through a module output is followed back to its source.

A representative list — the full live list is on /status.

Shown, not dropped

How a suppression looks in the PR comment

Set-aside findings are listed with their reason in the PR comment and marked suppressed in the SARIF upload. Each carries a plain-English rationale you can check.

🧠 audytx reasoned about 4 findings and chose not to flag them
· aws_lambda_function.api — DLQ not needed: this Lambda is only invoked synchronously via API Gateway; a DLQ would never receive an event
· aws_sqs_queue.jobs_dlq — this queue is itself the dead-letter target for jobs_queue; requiring a DLQ to have its own DLQ is infinite regress
· aws_dynamodb_table.sessions — PITR skipped: TTL is configured — this table is intentionally ephemeral; point-in-time recovery is mismatched for data that self-expires
· aws_lb.internal_admin — deletion protection lower risk: this is an internal load balancer with no internet route; the finding targets public-facing LBs

Every finding audytx sets aside is listed with its reason, so you can check each one.

Free plan

Start free

Install audytx on one repo, open a PR that touches your ECS, Lambda, or IAM resources, and read the reasoning block on the first scan.

FAQ

Questions teams ask

Doesn't suppression hide real issues?

Set-aside findings are listed with their reason in the PR comment and marked suppressed in the SARIF upload. Each one carries a plain-English explanation of why it was set aside, so you can check it.

What if audytx is wrong about the context, or I disagree?

audytx keeps a finding when it cannot confirm the context; every suppression is listed with its reason. If you think one is wrong, report it through the contact page.

Stop triaging false positives

Install audytx on one repo. Open a PR that touches your ECS, Lambda, or IAM resources. See the reasoning block — and how many findings don't make it through.

Install audytx free →

See audytx's own results: the benchmark →