What the agent does
The agent reads the module's shape before running any scanner, because a reusable module's defaults are its security posture. In a module shaped like terraform-aws-modules/terraform-aws-vpc, versions.tf requires Terraform 1.0 or newer and the AWS provider 6.28 or newer; main.tf is about 1,500 lines and variables.tf about 1,700, declaring the VPC, public, private, database, Redshift, ElastiCache and intra subnets, their route tables and network ACLs, NAT gateways and the default security group and network ACL adoption; vpc-flow-logs.tf holds the flow log, its CloudWatch log group and IAM role; modules/flow-log and modules/vpc-endpoints are submodules; examples/ has complete, flow-log, network-acls, block-public-access, ipv6-only and others; wrappers/ holds generated for_each wrappers. .pre-commit-config.yaml runs terraform_fmt, terraform_validate, terraform_docs and terraform_tflint with a named list of rules, and .github/workflows/pre-commit.yml runs that configuration on the minimum and maximum Terraform versions with TFLint v0.64.0. No Checkov, Trivy or tfsec configuration is present, so those findings will be new to the maintainers.
Then it reads the defaults that scanners flag and that a reader of the README might not notice. manage_default_security_group defaults to true with default_security_group_ingress and default_security_group_egress both [], so adopting the default security group strips its rules, which the report records as a sound default. manage_default_network_acl defaults to true with default_network_acl_ingress allowing all traffic from 0.0.0.0/0 and ::/0 at rules 100 and 101, which the report explains as AWS's own default made explicit, with the variable to tighten it. map_public_ip_on_launch defaults to false. enable_flow_log defaults to false, and when enabled the CloudWatch group's retention_in_days and kms_key_id both default to null, so logs never expire and use the service key unless the caller sets them; examples/flow-log sets a one-day retention and no key, and examples/complete leaves flow logs off. Each of these is written up as what the default is, what a scanner says about it, and which variable changes it.
The scanners run against both the module and its examples, because the examples are what a user copies. For each directory the agent runs terraform init -backend=false and terraform validate, then tflint with the repository's own rule list, then trivy config and checkov -d, which evaluate module code without AWS credentials. It separates findings into three groups: a default in variables.tf that a caller can change, an example that leaves a security feature off, and a resource definition that cannot be configured safely by any input. A scanner rule that fires on the module because the module intentionally lets callers choose, such as flow logs being optional, is listed with that reasoning rather than as a defect. Rules the agent could not evaluate, such as those needing a plan against a real account, are listed as not run.
The agent also checks the IAM policy in vpc-flow-logs.tf for the actions it grants the flow-log role, confirms the aws_default_security_group resource is created only when manage_default_security_group is true, and reads the block-public-access example against the aws_vpc_block_public_access_options resource in main.tf to describe what the module offers for the newer AWS control. It writes security-audit.md with a section per group, a table of scanner results per directory with the rule id, file and line, and a short list of suggested variable defaults for discussion. It changes no file and pushes nothing.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Audit this Terraform module for security problems and write security-audit.md. Read versions.tf, main.tf, variables.tf, vpc-flow-logs.tf, the modules directory, every directory under examples, .pre-commit-config.yaml and .github/workflows/pre-commit.yml first. For the root module and each example run terraform init -backend=false, terraform validate, tflint with the repository's rule list, trivy config and checkov. Read the defaults of manage_default_security_group, default_security_group_ingress and egress, manage_default_network_acl and its default rules, map_public_ip_on_launch, enable_flow_log and the flow log group's retention and KMS variables. Group findings into changeable defaults, examples that leave a feature off, and resource definitions no input can make safe. Give each finding the rule id, file and line, and the variable or change that addresses it. List rules you could not evaluate without an AWS account. Change no code.",
"resources": [
{
"url": "https://github.com/your-org/your-app"
}
]
}- Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
- Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
- Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.
What comes back
security-audit.md comes back as an artifact on the session, with a name, a mime_type and a url on api.prix.dev that downloads it with no key for about an hour; reading the session again returns a fresh link, and GET /o/{org}/sessions/{id}/artifacts/security-audit.md with the key works too. The report opens with the three groups of findings, each entry carrying the scanner, the rule id, the file and line and the variable or change that addresses it, then a table of validate, tflint, trivy and checkov results per directory, then the list of rules that need a real account to evaluate. The repository has no new commit.
A reviewer reads the changeable-defaults group first, since that is where a maintainer decides whether enable_flow_log or the log retention should change for everyone, and then the examples group, where turning a feature on costs nothing but shows users the secure shape. They can rerun any scanner line from the transcript against their own checkout; the commands and their full output are kept there, so a disputed finding can be traced to the exact rule that produced it.
Run it on every module release
When a release tag is pushed, your CI job sends this body to POST /o/{org}/sessions with resources naming the repository at that tag through a …/tree/<tag> URL, and a request_id, one UUID kept per tag, so a re-run of the job returns the same session. The Rush GitHub App has to be installed on the repository, or the resource is 422 RESOURCE_NOT_ACCESSIBLE.
A webhook_url on the API key delivers run.completed with session_url; your handler reads the session, downloads security-audit.md from its artifact url, and attaches it to the release notes so users of the module see what was checked.
The use case this job follows, with its automation and trigger: Produce a report or file, no repo.
Why run it on Rush?
Scanning a Terraform module by hand means installing four tools, running them in a dozen directories, and then arguing with yourself about which findings are real for a module whose job is to let callers choose. The agent installs the tools in its own sandbox, runs them everywhere, and does the sorting with the variables file open, so the report says which findings are defaults, which are examples and which are definitions.
Nothing touches an AWS account; validate, tflint, trivy config and checkov evaluate code only, and the report says which checks that leaves out. The transcript keeps every command and its output, so a maintainer can check a finding against the rule that raised it rather than against a summary.
Frequently asked questions
Will it open a pull request with safer defaults?
No. The prompt says change no code, and the result is security-audit.md. Defaults in a widely used module are a compatibility decision, so the report lists suggested changes with the variable name and the scanner rule behind each. A later run can change one default and open a pull request with the README and examples updated.
Does it need AWS credentials?
No. terraform init -backend=false and terraform validate need the provider schema only, and tflint, trivy config and checkov read the configuration files. Checks that need a plan or a live account, such as those about existing resources, are listed in the report as not evaluated.
Why are the examples scanned as well as the module?
Because users copy them. examples/complete is the shape most people start from, and it leaves enable_flow_log at its default of false; examples/flow-log shows the feature with a one-day retention. A finding on an example tells a maintainer where the secure shape should be shown, which a finding on variables.tf alone does not.
How does it treat the default network ACL's allow-all rules?
As a documented default, not a defect. default_network_acl_ingress reproduces what AWS gives every VPC, and manage_default_network_acl lets the module own it so a caller can tighten it in one variable. The report says that, cites the lines in variables.tf, and notes the scanner rule that fires on it so a reader is not surprised by it later.