Pre-Beta Pre-beta signups are open now. The full audytx engine is live for pre-beta. Everything free today stays free — paid tiers arrive Sep 01, 2026 from $20/month for unlimited repositories.
Getting Started · How audytx works

How to set up Terraform security scanning for your GitHub pull requests

audytx is a deterministic Terraform security engine for AWS, hand-written in Rust with no model in the loop. Identical input, identical findings, and every verdict cites the exact check and the relationship behind it.

266
checks — security, cost, reliability, ops
24
cross-resource reasoning axes
3
delivery stages — code, review, plan
~60s
to install · no CI wiring
One engine · three ways in

Pick a surface — the engine is the same

The same reasoning engine runs at code time, review time, and plan time. It flags issues but never blocks a merge.

GitHub App

Read-only install, one comment per PR plus SARIF. Install →

MCP server

The same engine your coding agent calls before the PR exists. Connect →

Plan enrichment

Opt-in: upload a resolved terraform plan for exact values. Enable →

Install the GitHub App

Click Install on GitHub, pick the repository, and approve — no CI wiring, no runners. The App requests these scopes:

Subscribed events: pull_request. We listen for opened, synchronize, and reopened — other actions (labels, edits, etc.) are ignored to keep noise down.

MCP server setup (coding agents)

The same engine is a hosted MCP server any MCP-capable agent (Claude Code, Cursor, and friends) can call before the PR exists. All you need is a free Client ID:

claude mcp add --transport http audytx https://audytx.com/mcp \
  --header "X-Client-ID: YOUR_CLIENT_ID"

Clients and gateways that inject standard OAuth-style headers can send the same Client ID as Authorization: Bearer YOUR_CLIENT_ID instead; both carriers are accepted. Auth failures return HTTP 401 with a WWW-Authenticate header per the MCP authorization spec, with RFC 9728 metadata served at /.well-known/oauth-protected-resource. Setup guides for Cursor, VS Code, JetBrains, Claude Desktop, and any stdio-only client (via mcp-remote) live at audytx.com/mcp#setup.

Two core tools:

Limits: 1000 files / 10 MB per call. File contents are processed in memory and never persisted — same privacy posture as the GitHub App path. scan_terraform also accepts an optional plan argument (your terraform show -json output) for the plan enrichment described below. Handy when the agent has already run a plan.

Terraform plan scanning (optional)

Static parsing can't resolve values behind variables, count/for_each expansion, or resources inside modules. Hand audytx the resolved plan and it scans with those final values folded in. Strictly opt-in and additive — the normal scan keeps working exactly as before; this only ever adds signal.

Add this workflow. It authenticates with the run's GitHub OIDC token — nothing to paste, no secret to store; audytx verifies the token and scopes it to your repo automatically:

# .github/workflows/audytx-plan.yml
on: [pull_request]
permissions:
  contents: read
  id-token: write        # lets the job mint an OIDC token
jobs:
  audytx-plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init -backend=false && terraform plan -out=tf.plan && terraform show -json tf.plan > plan.json
      - name: Upload plan to audytx
        env:
          AUD: https://audytx.com
        run: |
          OIDC=$(curl -sH "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
            "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=$AUD" | jq -r .value)
          PR=$(jq -r .number "$GITHUB_EVENT_PATH")
          SHA=$(jq -r .pull_request.head.sha "$GITHUB_EVENT_PATH")
          jq -n --slurpfile p plan.json \
            --arg repo "$GITHUB_REPOSITORY" --argjson pr "$PR" --arg sha "$SHA" \
            '{repo:$repo, pr_number:$pr, head_sha:$sha, plan:$p[0]}' > body.json
          curl -sf -X POST "$AUD/plan-upload" \
            -H "Authorization: Bearer $OIDC" -H "Content-Type: application/json" \
            --data-binary @body.json

Limits: 5 MB per upload, and the request must declare its size with a Content-Length header so it can be checked before the body is read — curl sets that for you in the command above. The pr_number and head_sha you send are checked against the real pull request: it must still be open, and the commit must be the tip of its branch right now, or the upload is refused. The usual innocent cause is a branch that moved while the job ran — rerun on the new commit. The plan JSON is processed in memory and never persisted — same posture as your source files. The PR comment notes a 🔬 plan-enhanced scan in its footer when plan data was used. If the upload fails for any reason, your normal scan still stands.

HCP Terraform run task · Beta

Review your HCP Terraform (and Terraform Enterprise) runs with the same engine, as a post-plan run task: HCP hands audytx the plan, audytx scans it and reports passed/failed back into the run with severity, message, and remediation per finding. The enforcement level you pick decides what happens next — advisory warns and continues, mandatory errors the run before apply.

Set it up in two steps:

  1. Create a free Client ID — the same one MCP uses.
  2. In HCP Terraform, open Settings → Run Tasks → Create a run task and enter:
    • Endpoint URL: https://audytx.com/run-task?client_id=YOUR_CLIENT_ID
    • HMAC key: your Client ID again — the same UUID. Every payload is signed with it, so only HCP can trigger your task. (No separate secret to manage.)
    Then attach the run task to a workspace at the post-plan stage and pick your enforcement level.

Authenticated by your Client ID and metered against the same free-tier monthly quota as MCP. The plan JSON is fetched from HCP, processed in memory, and never persisted — same privacy posture as the GitHub App path. If you're over quota, the task returns an advisory pass and skips the scan rather than blocking your run.

Open beta

Start free during the open beta

Install on GitHub, point your agent at the MCP server, and your next pull request gets its first review. Free for every team while the beta runs.

The catalog

What does audytx check?

266 checks across operations, security, reliability, and cost. Opinionated and AWS-only — we'd rather go deep on one cloud than shallow on five.

IAM
Wildcard policies, role trust, MFA, access-key hygiene.
Encryption
KMS / managed SSE across SQS, S3, RDS, DynamoDB, EBS, Secrets Manager.
Networking
Security-group exposure, VPC endpoints, ALB / NLB config.
Observability
CloudWatch alarms, retention, X-Ray, Lambda DLQ.
Reliability
Multi-AZ, backup retention, DLQ chains, dead-letter routing.
Cost
gp2 → gp3, idle NAT, oversized non-prod, missing cost-allocation tags.
Compliance refs
AWS FSBP, SOC 2 CC6, PCI-DSS, HIPAA annotated per finding.
Architecture smells
Stateful resources without lifecycle protection, hardcoded account/region, etc.

Context-aware reasoning

Most IaC scanners are single-resource pattern matchers: they flag a Lambda for a missing DLQ whether or not anything async invokes it. audytx pre-computes 24 cross-resource axes before evaluating each check. The four foundational ones:

DLQ identity

Which SQS queues are themselves a DLQ. A DLQ doesn't need its own DLQ.

Lambda invocation graph

Sync vs async-push vs polled-async. A Lambda DLQ only helps async-push.

Encryption variants

KMS-CMK vs AWS-managed vs service-managed SSE — all real encryption.

Data lifetime

DynamoDB TTL, S3 lifecycle, log retention. Ephemeral tables don't need PITR.

Checks consult these predicates as a post-filter — the check stays naive, the graph delivers the verdict — which is why legitimate patterns don't turn into false-positive noise.

The reasoning is visible. Findings the context layer reclassified as false positives don't silently disappear. Each appears in the PR comment under a collapsed 🧠 audytx reasoned about N findings and chose not to flag them block, with the check ID, the resource address, and a one-sentence rationale ("queue is itself a dead-letter queue", "Lambda is not invoked async-push", "table actively expires its own data via TTL"). The same reasoning rides into GitHub's Code Scanning Security tab as a SARIF suppressions[] justification — alerts there show as "closed (dismissed)" with the rationale visible in the alert detail. A reviewer sees everything audytx considered, including what it dismissed and why.

Live inventory of axes + the checks that consult each is available at /status under context_reasoning_axes.

GitHub Code Scanning integration (SARIF)

Alongside the PR comment, audytx uploads a SARIF v2.1.0 document to GitHub's Code Scanning API at every scan. Findings land in the repo's Security tab with file:line annotations, severity grouping, framework-tag filter chips (aws-fsbp-s3.1, soc2-cc6.1), and stable per-finding fingerprints so the same alert tracks across PR pushes.

SARIF severity mapping:

Critical + High → error Medium → warning Low + Informational → note

Requirements. SARIF upload needs either a public repo or a private repo with GitHub Advanced Security. Private repos without GHAS still get the full PR comment; the Security-tab upload just no-ops.

Reasoning visible in the Security tab. When the engine reasons a finding away as a false positive (see Context-aware reasoning), it still goes into the SARIF payload with a suppressions[] array carrying the justification. GitHub shows these as closed (dismissed) alerts — your security team gets the full record of what fired, what audytx dismissed, and why.

Baseline suppression

Add a .audytx-baseline.yaml file to your repo root. The expires: field is required — suppressions without an expiry rot into never-relitigated tech debt:

ignored_findings:
  - rule_id: AWS_LAMBDA_004
    resource_address: aws_lambda_function.api
    reason: "API GW sync invocation — DLQ is a semantic mismatch"
    expires: 2026-12-31
  - rule_id: AWS_IAM_001
    resource_address: aws_iam_role.legacy_admin
    reason: "Legacy admin role; removal scheduled Q3"
    expires: 2026-09-30

An expired entry stops suppressing and the finding reappears, forcing re-justification. Suppressed findings still appear in the comment under a "Suppressed" appendix so auditors see what was acknowledged.

From a coding agent (MCP): the scan_terraform, autofix_terraform, and dry_run_autofix tools accept an optional baseline argument — pass the contents of your .audytx-baseline.yaml as a string and the same baseline suppression applies, so findings you iterate on locally match what the PR check reports. The response itemizes each baseline-suppressed finding (with the matched rule/resource, its reason, and its expiry) in baseline_suppressed — a separate array from context_suppressed, so the two suppression kinds never merge — and reports a baseline_expired count; autofix won't touch a finding you've suppressed. A malformed baseline is returned as an error, never silently ignored.

Privacy Policy

Effective: 1 June 2026 · Operator: Rexstart Labs Pvt Ltd · Contact: open a support ticket

What we collect

What we do not collect

Data retention

Data location

All processing runs on our global network. Scan metadata is stored in a database in the US region. No data is transferred to third-party analytics, advertising, or data-broker services.

Changes

Material changes to this policy will be announced via the GitHub App release notes at least 14 days before taking effect. The effective date above is updated on each revision.

Terms of Service

Effective: 1 June 2026 · Operator: Rexstart Labs Pvt Ltd · Contact: legal@audytx.com

Acceptance

By installing the audytx GitHub App or sending requests to audytx.com/mcp, you agree to these terms. If you do not agree, uninstall the App and discontinue use.

Permitted use

Prohibited use

The following are strictly prohibited and will result in permanent account termination:

Reporting violations

Report abuse, violations of these terms, or suspected misuse via the abuse-report form. Include as much detail as possible: timestamps, GitHub usernames or installation IDs, and a description of the observed behavior. All reports are investigated. Confirmed violators are permanently banned from the GitHub App and the MCP endpoint, with no reinstatement path.

Service availability

Intellectual property

audytx's check catalog, engine, and all associated software are the property of Rexstart Labs Pvt Ltd. Your Terraform source code remains entirely your property. We claim no rights over the code you submit for analysis.

Disclaimer and limitation of liability

audytx is a static analysis tool. Findings are provided for informational purposes only and do not constitute a security audit, legal advice, or a guarantee that your infrastructure is free of vulnerabilities. Use findings as one input in your security review process, not as a substitute for it. To the maximum extent permitted by applicable law, Rexstart Labs Pvt Ltd is not liable for any damages arising from your use of or reliance on audytx findings.

Governing law

These terms are governed by the laws of India. Disputes shall be subject to the exclusive jurisdiction of the courts of Bangalore, Karnataka, India.

Current limits

AWS only — no Azure / GCP Terraform / HCL only Up to 400 Terraform files per scan Precision is the bar