Your Terraform planned clean and applied clean. Nothing in that pipeline checked whether the VPC you just created has flow logs, whether the log group is encrypted, or whether the security group you copied from a module allows the whole internet in. Six months later, an auditor asks.
tfsec, an open-source static analysis scanner from Aqua Security, catches those misconfigurations before they ship. It also no longer receives new features, because Aqua moved its engine into Trivy.
This post covers how tfsec works, how to configure it, and how to move to Trivy when you are ready.
We will cover:
What is tfsec?
tfsec is a static analysis scanner for Terraform code. It reads your configuration files, evaluates them against several hundred built-in rules, and reports misconfigurations with a severity, an impact statement, and a suggested fix. It runs locally or in CI.
Because the analysis is static, tfsec never touches your state or your cloud account. It covers AWS, Azure, Google Cloud, DigitalOcean, CloudStack, OpenStack, Oracle Cloud, GitHub, and Kubernetes.
tfsec parses HashiCorp Configuration Language (HCL) directly, so it evaluates expressions, functions such as concat(), and references between resources rather than matching text patterns.
Is tfsec still maintained?
Not actively. Aqua Security merged tfsec’s scanning engine into Trivy, and the repository now describes itself as part of Trivy. The last release, v1.28.14, shipped on May 2, 2025. tfsec tells you this itself. Every run prints the following to stderr:
======================================================
tfsec is joining the Trivy family
tfsec will continue to remain available
for the time being, although our engineering
attention will be directed at Trivy going forward.
You can read more here:
https://github.com/aquasecurity/tfsec/discussions/1994
======================================================The binary still works, and the checks it ships still catch real misconfigurations. It receives no new rules, so any cloud resource or provider attribute released after mid-2025 has no coverage. If you are choosing a scanner today, choose Trivy. If tfsec already runs in your CI, the migration section below covers the move.
Tfsec features
Let’s look at some of the top features that tfsec can use in our IaC workflows.
1. Comprehensive scanning of IaC
Tfsec can perform a thorough scan of the Terraform code, identifying potential vulnerabilities and misconfigurations before they are deployed into production. It supports AWS, Azure, and Google Cloud, so one tool covers your Terraform regardless of provider. Static analysis catches misconfigurations, not every class of security problem, so treat it as one layer rather than a guarantee.
2. Scanning modules and variables
tfsec scans your root module plus local and remote modules and variables. This feature provides a comprehensive view of our infrastructure’s security posture and ensures that our entire IaC is analyzed. Tfsec evaluates HCL expressions, allowing it to detect potential issues that may not be apparent when examining static values.
3. Detailed reporting and recommendations
Tfsec provides developers with detailed reports and recommendations for fixing detected issues, making it easy to understand and remediate potential vulnerabilities in developer-friendly output. Various output formats are available, allowing developers to choose the one that best suits their needs. Tfsec also includes links to relevant documentation from AWS, Azure, GCP, and Terraform, ensuring that developers have all the information they need to fix issues and adhere to best practices.
4. Integration with CI/CD pipelines
Tfsec is designed to integrate seamlessly with various CI/CD pipelines and IDEs, making it an important part of our development workflow. It can be easily integrated with popular CI/CD tools like GitHub Actions, GitLab CI, and Azure DevOps, allowing us to incorporate automated security scanning into your build and deployment processes.
5. Policy customization and extensibility
Tfsec offers the flexibility to define our custom policies and checks, ensuring that our IaC adheres to our organization’s specific security requirements. You can write custom checks in JSON or YAML, or write Rego policies and load them with --rego-policy-dir. Use --filter-results to run only named rules and --exclude to skip them.
The repository lists the rest, including Terraform CDK compatibility and expression evaluation.
Tfsec benefits
The list below highlights some of the compelling benefits and reasons why we should use tfsec.
1. Static analysis
As mentioned earlier, tfsec performs static analysis on Terraform configuration. Because of this static analysis, there is no need to even initialize the Terraform project or run the plan and apply commands. Tfsec checks for misconfigurations in the directory where all the Terraform config files exist.
2. Built-in checks
Tfsec supports major cloud providers like AWS, Azure, GCP, and other cloud platforms. It aalso includes checks for Kubernetes, GitHub, and OpenStack. If you have never used any kind of checks on your Terraform project, then these exhaustive checks are a great place to begin as they readily highlight the security shortcomings in current configuration. This offsets the efforts required to learn the lessons and then implement security best practices.
3. Ease of use
Installing and getting started with tfsec locally is quite easy. It also supports DevOps pipeline tasks for GitHub Actions, Azure DevOps, and others. If we implement custom checks, they are automatically verified in any automation or CI workflow.
The tfsec CLI output displays all the misconfigurations in a well-formatted manner, along with their severity. It also offers the output to be stored in a file in multiple user-friendly formats as build artifacts.
4. Rule provenance
The built-in rules came from years of community contribution, and the same rule set now ships inside Trivy under Aqua Vulnerability Database (AVD) IDs. Work you do against tfsec rules carries over.
5. Module scanning
We use modules to save time when developing our infrastructure and often trust the module developer as far as internal working and security are concerned. In this scenario, tfsec also scans the modules, making sure they meet the security best practices.
How to use tfsec?
Step 1: Install tfsec
Install tfsec using one of the methods below, then confirm the binary is on your PATH with tfsec --version.
tfsec is available for different platforms, including Windows, macOS, and Linux. We can either download the binary from the official GitHub repository or use a package manager like Homebrew (for macOS) or Chocolatey (for Windows). Once installed, we need to ensure that the tfsec command is accessible from your command line.
Step 2: Run the tfsec command
Navigate to the directory containing our Terraform code and execute the tfsec command followed by the appropriate flags. By default, tfsec scans all .tf and .tfvars files in the current directory and its subdirectories. It analyzes our Terraform configuration files and provides security-related feedback and recommendations.
Step 3: Customize the output
We can customize the tfsec behavior by using flags such as --exclude to exclude certain directories or files, or --severity to filter results by severity level. The output is displayed in our terminal, and we can review the issues reported by tfsec to identify potential security vulnerabilities in our Terraform code.
Step 4: Use custom inputs
Then using the Custom Inputs feature, we can integrate tfsec (or Checkov, Terrascan, Kics, and others) in our workflows with Spacelift. Security is one of Spacelift’s biggest priorities, so there are also state-of-the-art security solutions that are embedded inside the product, like Policy as Code, Encryption, Single Sign On (SSO), and Private Worker Pools.
Read more about integrating security tools with Spacelift.
Using TFsec to Secure Terraform Code

How to install tfsec?
In this section, we’ll go over the installation process for tfsec on various platforms like Linux, MacOS, and Windows.
How to install tfsec on Linux
Download the tfsec binary by running the command below.
curl -L "$(curl -s https://api.github.com/repos/aquasecurity/tfsec/releases/latest | grep -o -E "https://.+tfsec-linux-amd64")" -o tfsecChange the permissions of the downloaded file to execute the same.
chmod +x tfsecMove this file under the bin directory, making sure the path to the bin directory is added to the PATH environment variable.
sudo mv tfsec /usr/local/binAlternatively, run a single command below, which effectively performs all the tasks above.
curl -s https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_linux.sh | bashHow to install tfsec on macOS
Tfsec can be installed using Homebrew on macOS-based systems. To install, run the command below in a terminal.
brew install tfsecHow to install tfsec on Windows
Tfsec can be installed on Windows-based systems using the Chocolatey package manager.
choco install tfsecHow to install tfsec using go
If go is installed on any system, then the package managers above are not needed. It is also possible to install tfsec using go, by running the command below. This installs the latest version of tfsec.
go install github.com/aquasecurity/tfsec/cmd/tfsec@latestHow to install tfsec using Docker image
Alternatively, if Docker is installed on our system, and if we do not want to go through the installation process, we can run a quick scan using the official tfsec Docker image as shown in the example below.
docker run --rm -it -v "$(pwd):/src" aquasec/tfsec /srcHere, the /src directory is where all the Terraform files and sub-directories exist.
Working with tfsec locally
Let’s begin by installing and using tfsec locally in one of our Terraform projects.
Once installed, we can create a Terraform project directory and add a main.tf file in it. We will attempt to create a VPC using the minimum required configuration and run tfsec in-built checks against it.
The code below shows the minimal configuration required to create a VPC in AWS using Terraform.
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
tags = {
name = "main"
}
}At this point, the code is capable of creating the VPC with no problems.
However, to be sure about security practices being followed, let us run the tfsec scan in this directory. Open the terminal and navigate to this project directory. Run the command below.
tfsec .Understanding the tfsec output
The output should look similar to the one below.
Result #1 MEDIUM VPC Flow Logs is not enabled for VPC
────────────────────────────────────────────────────────────────────────────────────────────────────────
main.tf:1-7
────────────────────────────────────────────────────────────────────────────────────────────────────────
1 resource "aws_vpc" "main" {
2 cidr_block = var.vpc_cidr
3 enable_dns_hostnames = true
4 tags = {
5 name = "main"
6 }
7 }
────────────────────────────────────────────────────────────────────────────────────────────────────────
ID aws-ec2-require-vpc-flow-logs-for-all-vpcs
Impact Without VPC flow logs, you risk not having enough information about network traffic flow to investigate incidents or identify security issues.
Resolution Enable flow logs for VPC
More Information
- https://aquasecurity.github.io/tfsec/v1.28.1/checks/aws/ec2/require-vpc-flow-logs-for-all-vpcs/
────────────────────────────────────────────────────────────────────────────────────────────────────────
timings
──────────────────────────────────────────
disk i/o 61.375µs
parsing 177.375µs
adaptation 70.834µs
checks 3.057291ms
total 3.366875ms
counts
──────────────────────────────────────────
modules downloaded 0
modules processed 1
blocks processed 7
files read 3
results
──────────────────────────────────────────
passed 2
ignored 0
critical 0
high 0
medium 1
low 0
2 passed, 1 potential problem(s) detected.Instead of reading from the top, let us read the output from bottom to up, as all the result details are summarized at the end.
The last line indicates how many checks have passed – two in this case and the number of potential problems detected by tfsec – one in this case.
The section above this line summarizes the results by providing various counts. The meaning of the count is explained below.
- Passed – This is the number of checks that were passed by tfsec, and no action is required to close these gaps.
- Ignored – tfsec ignores some checks due to several reasons. It is possible to skip a certain check explicitly, which we will cover in the next section.
- Critical, high, medium, low – each tfsec check is associated with a level of severity or impact. Any failed check is counted against the respective severity. In our example, we have encountered a medium severity check.
Note: tfsec does not prevent Terraform from applying these changes. It is still perfectly fine to provision infrastructure without addressing the problems identified by tfsec. However, it is highly encouraged to resolve them for more secure infrastructure.
The next section above “results” is “counts”. These counts indicate the “code coverage” of the Terraform configuration. The counts are explained below.
- Modules downloaded – if our configuration reuses any externally downloaded modules, then all those modules are counted here.
- Modules processed – tfsec treats the Terraform configuration included in the current directory as a module being scanned. Thus, this count value is calculated as the sum of all the externally downloaded modules + 1.
- Blocks processed – number Terraform blocks processed by tfsec. Currently, in my Terraform configuration, apart from the VPC block, there are additional blocks for variables and providers. Thus the count is 7.
- Files read – all the configuration blocks are spread across three files – namely “main.tf”, “provider.tf”, and “variables.tf”.
The timings section above “counts” represents the system stats used by tfsec to perform these checks. Tfsec is quite fast, so it usually does not cause any drastic performance impact.
The next sections above “timings” describe each problem in detail. The details of each problem are described with the information listed below.
- The severity of the problem detected
- Short description
- Location of the resource block where the problem exists.
- ID of the check, which can be used to refer to the associated documentation.
- Description of the impact to help us decide next actions
- Resolution suggestion
- More information with links to appropriate documentation
Ignoring tfsec checks
Let’s pretend that the problem highlighted by tfsec is not that important to us and that it would be okay to ignore it. We can inform it to tfsec by adding a comment at the top of the resource block where this problem exists.
The format in which the comment needs to be added is shown below.
#tfsec:ignore:<check-id>Our modified code should look like the one below. We have picked up the ID from the previous tfsec terminal output.
#tfsec:ignore:aws-ec2-require-vpc-flow-logs-for-all-vpcs
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
tags = {
name = "main"
}
}Run the tfsec command again and observe the output below.
timings
──────────────────────────────────────────
disk i/o 410.167µs
parsing 318.376µs
adaptation 1.701375ms
checks 3.9175ms
total 6.347418ms
counts
──────────────────────────────────────────
modules downloaded 0
modules processed 1
blocks processed 7
files read 3
results
──────────────────────────────────────────
passed 2
ignored 1
critical 0
high 0
medium 0
low 0
No problems detected!Since we had only one problem detected by tfsec, and we have chosen to ignore it, tfsec now highlights “No problems detected!”.
Note how the ignored count is incremented by one in the counts section of the output.
Addressing tfsec problems
Now, re-enable the check and let tfsec highlight the problem once again. This time, instead of ignoring the problem, we will address and resolve it, adhering to the suggested best practices.
The tfsec CLI output suggests the resolution of enabling flow logs for VPC. This is indeed important since, in the absence of flow logs, it would not be easily possible to debug any incoming and outgoing traffic – both internally and externally. Thus flow logs help us in capturing this information.
To associate our VPC with flow logs, we first need to create the flow log resource in our Terraform config. Additionally, we also have to create a CloudWatch log group to store our logs. This is followed by creating an appropriate IAM role, policy, and policy document, as shown in the updated main.tf file below.
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
tags = {
name = "main"
}
}
resource "aws_flow_log" "vpc_flow_log" {
iam_role_arn = aws_iam_role.example.arn
log_destination = aws_cloudwatch_log_group.example.arn
traffic_type = "ALL"
vpc_id = aws_vpc.main.id
}
resource "aws_cloudwatch_log_group" "example" {
name = "example"
}
data "aws_iam_policy_document" "assume_role" {
statement {
effect = "Allow"
principals {
type = "Service"
identifiers = ["vpc-flow-logs.amazonaws.com"]
}
actions = ["sts:AssumeRole"]
}
}
resource "aws_iam_role" "example" {
name = "example"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}
data "aws_iam_policy_document" "example" {
statement {
effect = "Allow"
actions = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
]
resources = ["*"]
}
}The first impression is that the number of LOC has drastically increased. This may not always be the case, as some problems highlighted by tfsec can be resolved by adding one attribute to the existing resources.
However, this also highlights the fact that it is easy to skip such measures for the sake of convenience and ease.
If we perform the tfsec scan now, the tfsec will also identify potential problems in all the additional resources we have included to resolve the problem with VPC. It is possible that tfsec will highlight more problems.
Run the tfsec command and observe the output below.
Result #1 LOW Log group is not encrypted.
────────────────────────────────────────────────────────────────────────────────────────────────────────
main.tf:16-18
────────────────────────────────────────────────────────────────────────────────────────────────────────
16 resource "aws_cloudwatch_log_group" "example" {
17 name = "example"
18 }
────────────────────────────────────────────────────────────────────────────────────────────────────────
ID aws-cloudwatch-log-group-customer-key
Impact Log data may be leaked if the logs are compromised. No auditing of who have viewed the logs.
Resolution Enable CMK encryption of CloudWatch Log Groups
More Information
- https://aquasecurity.github.io/tfsec/v1.28.1/checks/aws/cloudwatch/log-group-customer-key/
- https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group#kms_key_id
────────────────────────────────────────────────────────────────────────────────────────────────────────
timings
──────────────────────────────────────────
disk i/o 67.708µs
parsing 394.125µs
adaptation 79.375µs
checks 4.804958ms
total 5.346166ms
counts
──────────────────────────────────────────
modules downloaded 0
modules processed 1
blocks processed 12
files read 3
results
──────────────────────────────────────────
passed 3
ignored 0
critical 0
high 0
medium 0
low 1
3 passed, 1 potential problem(s) detected.This time, tfsec has checked four policies, ignored none – since we removed the ignore comment for the VPC resource, and detected a potential problem with low severity. This problem has nothing to do with VPC, as the result details do not indicate the same. We have been successful in addressing the medium-severity issue with VPC!
However, the new problem that has cropped up is related to the CloudWatch log group.
As a best practice, it is recommended to enable encryption on the log group. It is a fairly straightforward problem to resolve. This time, the resolution does not involve the need to add more resource blocks, but simply add an attribute to aws_cloudwatch_log_group resource block, as shown below.
resource "aws_cloudwatch_log_group" "example" {
name = "example"
kms_key_id = "mykmskey"
}Run the tfsec scan again and observe the stats.
timings
──────────────────────────────────────────
disk i/o 72.71µs
parsing 420.666µs
adaptation 95.167µs
checks 2.012208ms
total 2.600751ms
counts
──────────────────────────────────────────
modules downloaded 0
modules processed 1
blocks processed 12
files read 3
results
──────────────────────────────────────────
passed 4
ignored 0
critical 0
high 0
medium 0
low 0
No problems detected!We have now resolved all the issues highlighted by tfsec, which has resulted in a safer VPC configuration. Note that we have not even initialized our Terraform project.
However, if we had used any external modules, initialization would have required downloading the Terraform configuration specific to those modules.
Tfsec in SecOps pipeline
Until now, we have used tfsec to test our Terraform configuration locally. This time, we are going to use this in the DevOps pipeline.
The ability of the tfsec to perform these checks before applying the infrastructure changes is a great asset as it prevents unsafe misconfigurations from affecting the environment.
Using tfsec with GitHub action
Both GitHub Actions and Azure DevOps support tfsec tasks, which perform similar scans to the ones we did in the previous section, before promoting the changes to higher environments.
For this example, I have pushed my code to a GitHub repository and created a sample GitHub action. Searching for “tfsec” in the marketplace provides us with several options, as shown below. Select the first action.

Using the default values, the pipeline job should have a task as seen below.

tfsec returns a detailed exit code, which is what your pipeline gates on:
0 No failed checks
2 Failed checks, all of them LOW severity
1 At least one CRITICAL, HIGH, or MEDIUM failureUse --soft-fail to report findings without failing the build, which is the usual first step when you add tfsec to an existing repository. Combine --minimum-severity HIGH with a hard fail once the backlog is clear.
Tfsec custom checks
We may come across situations where the built-in checks offered/contributed by the community do not meet the security requirements set by the organizations. In such cases, it is also possible to define custom checks for tfsec.
In this section, we create a custom check in tfsec that makes it mandatory to include the “Environment” tag on all AWS resources.
To begin implementing a custom check, create a subdirectory named “.tfsec”, and a YAML file named “_tfchecks.YAML” within this directory. The directory structure should look like the one below.

It is also possible to define custom checks in JSON format. However, we will stick to YAML for this example.
Add the contents below to the _tfchecks.YAML file, and then we will go through the explanations in detail.
---
checks:
- code: MYCUSTOMCHECK_TAGS
description: Custom check to ensure the Environment tag is applied to All resources
impact: By not having Environment we can't keep track of billing
resolution: Add the Environment tag
requiredTypes:
- resource
requiredLabels:
- aws_*
severity: CRITICAL
matchSpec:
name: tags
action: contains
value: Environment
errorMessage: The required Environment tag was missing
relatedLinks:
- http://example-org/docs/sec/tagging.htmlAt first glance, the information in this YAML file appears very similar to the CLI output for all problems detected by tfsec.
This is where we define all those attributes that tfsec depends on to generate highly informative output. This can also be understood as a “test case” for our Terraform configuration.
The contents of this file are explained in more detail below.
- checks – At the very top level, the “checks:” keyword indicates that the lines below define custom checks. All the custom check definitions come under this.
- code – Every check needs to have a code associated with it. There are a couple of uses for having a well-defined code format. First, it helps to ignore this check wherever required in the Terraform configuration. The URL to the documentation may incorporate this code for better organization.
- description – Describes the issue that needs to be addressed, to resolve this check.
- impact – Describes the impact of this if it is not resolved.
- resolution – Suggestions/solution to resolve.
- requiredTypes – This specifics which types of Terraform blocks this particular check applies to.
- requiredLabels – Here we can have granular control over the application of checks. We can specify a particular resource like “aws_vpc”, or “aws_instance”, to apply this check only to these types of resources. However, wildcards are also supported here. Since we want this check to be applied to all the AWS resources, we have expressed the same as “aws_*”.
- severity – This is where we define the severity of this problem. This attribute is counted as “critical” in results since we have mentioned it to be a CRITICAL issue here.
- matchSpec – This is where we actually define the enforcement of this check. It is defined with the help of name, action, and value attributes. The name defines the property to be checked against the value supplied. To execute this comparison, we make use of the action attribute. In this case, we have used “Environment” to make sure the Environment attribute is used in Tags. For all the available actions, refer to this document.
- errorMessage – Error message to display in case this check fails.
- relatedLinks – URLs to the relevant documentation for more information or resolution.
Having this custom check saved, let’s run the tfsec scan. We don’t need to explicitly supply any argument here, since tfsec automatically incorporates this custom check in its scan. We also know that none of our Terraform resources implement the Environment tags, so we can already expect some errors.
Run tfsec, and observe the output.
Result #4 CRITICAL Custom check failed for resource aws_flow_log.vpc_flow_log. The required Environment tag was missing
────────────────────────────────────────────────────────────────────────────────────────────────────────
main.tf:9-14
────────────────────────────────────────────────────────────────────────────────────────────────────────
9 resource "aws_flow_log" "vpc_flow_log" {
10 iam_role_arn = aws_iam_role.example.arn
11 log_destination = aws_cloudwatch_log_group.example.arn
12 traffic_type = "ALL"
13 vpc_id = aws_vpc.main.id
14 }
────────────────────────────────────────────────────────────────────────────────────────────────────────
ID custom-custom-mycustomcheck_tags
Impact By not having Environment we can't keep track of billing
Resolution Add the Environment tag
More Information
- http://example-org/docs/sec/tagging.html
────────────────────────────────────────────────────────────────────────────────────────────────────────
timings
──────────────────────────────────────────
disk i/o 1.189543ms
parsing 409.291µs
adaptation 88.083µs
checks 4.0085ms
total 5.695417ms
counts
──────────────────────────────────────────
modules downloaded 0
modules processed 1
blocks processed 12
files read 3
results
──────────────────────────────────────────
passed 4
ignored 0
critical 4
high 0
medium 0
low 0
4 passed, 4 potential problem(s) detected.As expected, tfsec has detected four problems. Note that there are 12 blocks, and only four are expecting Environment tags to be present. The classification of these blocks is as follows:
- Variable blocks – 3
- Provider related blocks – 3
- Data sources – 2
Since our custom check specifies “requiredTypes” to be “resource”, this check is not applied to the above list.
We can resolve this issue by adding the environment tags to all four resource blocks and running the tfsec again. Optionally, we can also choose to ignore these checks by adding appropriate comments, as discussed before.
In the code below, we have ignored the custom Tag check for “aws_flow_log” and “aws_iam_role” resources.
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
tags = {
name = "main"
Environment = "dev"
}
}
#tfsec:ignore:MYCUSTOMCHECK_TAGS
resource "aws_flow_log" "vpc_flow_log" {
iam_role_arn = aws_iam_role.example.arn
log_destination = aws_cloudwatch_log_group.example.arn
traffic_type = "ALL"
vpc_id = aws_vpc.main.id
}
resource "aws_cloudwatch_log_group" "example" {
name = "example"
kms_key_id = "mykmskey"
tags = {
Environment = "dev"
}
}
#tfsec:ignore:MYCUSTOMCHECK_TAGS
resource "aws_iam_role" "example" {
name = "example"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}If we run tfsec now, no problems should be detected. We have successfully implemented custom checks using tfsec.
How to migrate from tfsec to Trivy
Trivy runs the same rule engine tfsec contributed, so most migrations are a command swap. Current Trivy release is v0.73.0.
| Task | tfsec | Trivy |
| Scan a directory | tfsec ./infra | trivy config ./infra |
| Pass tfvars | tfsec ./infra –tfvars-file dev.tfvars | trivy config –tf-vars dev.tfvars ./infra |
| Set output format | tfsec –format sarif | trivy config –format |
| Filter by severity | tfsec -m HIGH | trivy config –severity |
| Skip a directory | tfsec –exclude-path test | trivy config –skip-dirs test |
| Custom checks | –custom-check-dir / –rego-policy-dir | –config-check |
| Ignore inline | #tfsec:ignore:<rule> | #trivy:ignore:<rule> |
| Ignore by file | .tfsec/config.yml excluded_checks | .trivyignore |
| Fail the build | exit code 0 / 1 / 2 by severity | –exit-code 1 |
Three differences worth planning for:
Trivy pulls its rule bundle from a container registry, so rules update without a Trivy upgrade. tfsec embedded them in the binary.
Trivy exits 0 by default even when it finds problems. Set --exit-code 1 or put exit-code: 1 in trivy.yaml, otherwise your pipeline goes green.
Trivy accepts a rule’s AVD ID, short code, or alias in ignore comments, so your existing #tfsec:ignore:aws-ec2-require-vpc-flow-logs-for-all-vpcs rewritten as #trivy:ignore:aws-ec2-require-vpc-flow-logs-for-all-vpcs resolves correctly. You do not have to look up every AVD number.
Aqua’s own migration guide covers the rest.
tfsec alternatives and successors
Here are some of the tfsec alternatives.
1. Trivy
Trivy is the direct successor. Aqua merged tfsec’s engine into it, and trivy config scans Terraform, CloudFormation, Kubernetes manifests, Helm charts, Dockerfiles, and Azure ARM templates with the same rule set. Rules update from a remote registry rather than shipping in the binary. If you run tfsec today, this is where you go.
2. Checkov
Checkov is the most active open-source alternative, with over 1,000 built-in policies across Terraform, CloudFormation, Kubernetes, Helm, ARM, and Serverless. It is maintained by Palo Alto Networks as part of Prisma Cloud and releases frequently, with version 3.3.9 shipping in August 2026. Policies are written in Python or YAML, and it supports graph-based checks that follow references between resources.
3. KICS
KICS, from Checkmarx, scans Terraform, Kubernetes, Docker, CloudFormation, Ansible, Helm, and OpenAPI against roughly 2,000 queries written in Rego. It is actively released and a reasonable choice if you want one scanner across configuration formats beyond IaC.
Tools no longer worth adopting
Terrascan was archived by Tenable on November 20, 2025 and is no longer maintained.
Bridgecrew is not a separate product. Palo Alto Networks acquired it in 2021 and folded it into Prisma Cloud. Its scanner is Checkov.
Key points
In this post, we have explored tfsec and implemented the same in creating a Terraform configuration for VPC. tfsec is a powerful and fast tool that highlights the security gaps solely by reading the configuration files and the relationships between the resources. It is quite intelligent in analyzing deeper aspects of Terraform configuration language (HCL).
Leveraging tfsec provides a very precious offset to teams, which otherwise are the hard-learned lessons from security perspectives. We also implemented custom checks, and took an overview of other alternatives to tfsec.
A scanner tells you the code is wrong. It does not stop the apply. Spacelift runs tfsec, Trivy, Checkov, or KICS as a gate on every run, enforces policy as code on the plan itself, and issues short-lived cloud credentials per run instead of a static key pair on someone’s laptop.
Read more about integrating security tools with Spacelift.
Note: Terraform moved to the BUSL license starting with version 1.6, so version 1.5.x and earlier remains open source under MPL 2.0. OpenTofu is an open-source fork of Terraform, created from version 1.5.6, that expands on Terraform’s existing concepts. It is a viable alternative to HashiCorp’s Terraform.
The most flexible management platform for Infrastructure as Code
Spacelift allows you to automate, audit, secure, and continuously deliver your infrastructure. It helps overcome common state management issues and adds several must-have features for infrastructure management.
Frequently asked questions
What does tfsec do?
tfsec scans Terraform configuration files to detect security misconfigurations before deployment, including overly permissive security groups, missing encryption, and disabled logging. It runs locally or in CI and returns a non-zero exit code when it finds problems. Its engine now ships inside Trivy.
Is tfsec deprecated?
tfsec is not formally deprecated, but it is no longer developed. Aqua Security merged its scanning engine into Trivy, and the last release, v1.28.14, shipped in May 2025. Every tfsec run prints a notice that engineering attention has moved to Trivy. The binary still works and its existing checks still fire, but it gets no new rules, so resources released after mid-2025 are uncovered. Use Trivy for new work.
What is the difference between Terrascan and tfsec?
Neither is a current recommendation. Terrascan scanned Terraform, Kubernetes, Helm, and CloudFormation, but Tenable archived it in November 2025 and it is no longer maintained. tfsec covers Terraform only and stopped receiving releases in May 2025. For multi-format scanning today, use Trivy, Checkov, or KICS.
