This check flags CodeBuild projects that write build artifacts to S3 without encryption, leaving compiled binaries, config files, and sometimes secrets readable to anyone with bucket access. Fix it by setting an encryptionKey (a KMS key) on the project's artifacts configuration.
CodeBuild is the workhorse of a lot of AWS pipelines. It compiles source, runs tests, packages containers, and drops the results, your build artifacts, into S3. By default CodeBuild encrypts those artifacts with the AWS managed key for S3. But that behavior can be turned off, either explicitly through the encryptionDisabled flag or by misconfiguring the artifact block in Terraform or CloudFormation. When it is off, your build output lands in S3 as plaintext objects.
This check, cicd_codebuild_unencrypted, looks at every CodeBuild project in your account and reports any project where artifact encryption has been disabled.
What this check detects
The check inspects the artifacts (and secondaryArtifacts) configuration of each CodeBuild project. It fails when:
- The artifact
encryptionDisabledproperty is set totrue, or - No KMS key is associated with the project for artifact encryption while encryption has been explicitly turned off
A passing project either uses a customer managed KMS key (CMK) or falls back to the default AWS managed key for S3 with encryption left enabled.
Note: CodeBuild encrypts artifacts by default using the aws/s3 managed key. The only way artifacts end up unencrypted is if someone sets encryptionDisabled = true. So a failure here is almost always a deliberate (or copy-pasted) choice rather than a default.
Why it matters
Build artifacts are easy to dismiss as throwaway files, but in practice they are one of the richest targets in a cloud account. Here is what actually ends up in artifact buckets:
- Compiled application code that an attacker can decompile to find logic flaws, hardcoded endpoints, or internal API structures
- Configuration files with database hostnames, feature flags, and occasionally credentials that were never meant to leave the pipeline
- Container images and deployment packages that get pulled straight into production
- Test reports and logs that leak schema details and internal naming conventions
When these objects are unencrypted, two real risks open up. First, anyone who gains read access to the S3 bucket, through an over-permissive bucket policy, a leaked IAM key, or a misconfigured VPC endpoint, can read the artifacts directly. There is no second layer of protection. Second, you fail the encryption-at-rest requirements that show up in almost every compliance framework, including PCI DSS, HIPAA, SOC 2, and FedRAMP. An auditor finding plaintext build output in S3 is a finding you have to remediate before sign-off.
The supply chain angle is the one that bites hardest. If an attacker can read your artifacts, they can study them. If they can also write to the bucket, which often comes with read access in poorly scoped policies, they can swap a clean binary for a tampered one. Your next deployment ships their payload. Encryption with a CMK gives you an extra access boundary here, because reading or writing the object requires kms:Decrypt or kms:GenerateDataKey on the key, not just S3 permissions.
Warning: Encryption protects data at rest, not access control. A CMK reduces the blast radius, but you still need a tight bucket policy and IAM scoping. Treat encryption as one layer, not the whole defense.
How to fix it
The fix is to enable encryption on the artifacts configuration and ideally point it at a customer managed KMS key so you control the key policy and rotation.
Console
- Open the CodeBuild console and select the affected project
- Choose Edit, then Artifacts
- Expand Additional configuration
- Uncheck Disable artifacts encryption if it is set
- Under Encryption key, select your customer managed KMS key (or leave it on the default AWS managed key if a CMK is not warranted)
- Save the project
AWS CLI
First, check the current artifact encryption state for a project:
aws codebuild batch-get-projects \
--names my-build-project \
--query 'projects[0].artifacts.encryptionDisabled'
If it returns true, update the project to re-enable encryption and attach a CMK:
aws codebuild update-project \
--name my-build-project \
--artifacts '{
"type": "S3",
"location": "my-artifact-bucket",
"encryptionDisabled": false
}' \
--encryption-key arn:aws:kms:us-east-1:111122223333:key/abcd1234-5678-90ab-cdef-EXAMPLE11111
Note: The --encryption-key argument on update-project sets the project-level key used for artifacts and exported environment variables. The per-artifact encryptionDisabled flag overrides it, so make sure that flag is false.
Terraform
If you manage CodeBuild with Terraform, the offending config usually looks like this:
resource "aws_codebuild_project" "build" {
name = "my-build-project"
service_role = aws_iam_role.codebuild.arn
artifacts {
type = "S3"
location = aws_s3_bucket.artifacts.bucket
encryption_disabled = true # this is the problem
}
# ...
}
Fix it by setting encryption_disabled to false and providing a CMK on the project:
resource "aws_codebuild_project" "build" {
name = "my-build-project"
service_role = aws_iam_role.codebuild.arn
encryption_key = aws_kms_key.codebuild.arn
artifacts {
type = "S3"
location = aws_s3_bucket.artifacts.bucket
encryption_disabled = false
}
# ...
}
Warning: Customer managed KMS keys cost roughly $1 per month per key plus per-request charges. For high-volume pipelines the request charges are usually negligible, but multiply that across hundreds of keys and it adds up. Share one key across related projects rather than minting a key per project.
CloudFormation
{
"Type": "AWS::CodeBuild::Project",
"Properties": {
"Name": "my-build-project",
"EncryptionKey": "arn:aws:kms:us-east-1:111122223333:key/abcd1234-...",
"Artifacts": {
"Type": "S3",
"Location": "my-artifact-bucket",
"EncryptionDisabled": false
}
}
}
Danger: If you create a new CMK and your CodeBuild service role does not have kms:GenerateDataKey and kms:Decrypt on that key, builds will fail to write artifacts. Update the key policy or the role policy before you flip projects over, or you will break running pipelines.
The minimum key permissions the CodeBuild role needs:
{
"Effect": "Allow",
"Action": [
"kms:GenerateDataKey",
"kms:Decrypt",
"kms:DescribeKey"
],
"Resource": "arn:aws:kms:us-east-1:111122223333:key/abcd1234-..."
}
How to prevent it from happening again
Remediating one project is fine, but the goal is to stop the misconfiguration from reaching your account in the first place. A few layers work well together.
Block it in IaC review with policy-as-code
Run a policy check in CI that rejects any CodeBuild project with encryption disabled. Here is an OPA/Rego rule against a Terraform plan:
package codebuild.encryption
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_codebuild_project"
resource.change.after.artifacts[_].encryption_disabled == true
msg := sprintf("CodeBuild project '%s' has artifact encryption disabled", [resource.address])
}
If you use Checkov, the built-in check CKV_AWS_78 already covers this and needs no custom rule.
checkov -d . --check CKV_AWS_78
Tip: Wire the policy check into a pull request gate so the pipeline fails before merge. Catching this at plan time costs seconds. Catching it after an auditor finds it costs a remediation sprint.
Detect drift continuously
People still make changes in the console or with one-off CLI commands, so a plan-time gate is not enough on its own. Lensix scans live CodeBuild projects and flags any that drift into an unencrypted state, which catches the cases that bypassed your IaC pipeline.
Enforce at the organization level
You cannot directly block encryptionDisabled with a service control policy, but you can require that build artifact buckets enforce SSE through bucket policies and SCPs that deny unencrypted s3:PutObject. That gives you a backstop even if a project tries to write plaintext.
{
"Sid": "DenyUnencryptedArtifactUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::my-artifact-bucket/*",
"Condition": {
"Null": { "s3:x-amz-server-side-encryption": "true" }
}
}
Best practices
- Use a customer managed key, not just the default. A CMK lets you control who can decrypt artifacts through the key policy, enable automatic rotation, and audit usage in CloudTrail. The AWS managed key gives you encryption but no granular control.
- Scope the artifact bucket tightly. Encryption is the last line, not the first. Lock down the bucket policy so only the CodeBuild role and the deploy stage can read artifacts.
- Apply the same rule to secondary artifacts and S3 caches. Projects with multiple outputs or an S3 cache can have encryption disabled on those too. Check the full
secondaryArtifactsand cache config, not just the primary block. - Set a lifecycle policy on the artifact bucket. Old build output piles up. Expiring artifacts after a sensible window reduces both your storage bill and the amount of sensitive data sitting around.
- Keep secrets out of artifacts entirely. Encryption helps, but the real fix for leaked credentials is never writing them to an artifact. Pull secrets at runtime from Secrets Manager or SSM Parameter Store.
Re-enabling artifact encryption is a small change with an outsized payoff. It closes a quiet supply chain gap, satisfies your encryption-at-rest controls, and costs almost nothing. Find the projects where it slipped, fix them, and gate it in CI so it stays fixed.

