AWS CodeBuild - Untrusted PR Webhook Bypass (CodeBreach-style)
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Este vector de ataque aparece cuando un flujo de trabajo de PR público está conectado a un proyecto de CodeBuild privilegiado con controles de webhook débiles.
Si un atacante externo puede hacer que CodeBuild ejecute su pull request, normalmente puede obtener arbitrary code execution inside the build (scripts de build, hooks de dependencias, scripts de pruebas, etc.), y luego pivotar hacia secretos, credenciales IAM o credenciales del proveedor de código fuente.
Por qué esto es peligroso
Los filtros de webhook de CodeBuild se evalúan con patrones regex (para filtros que no son EVENT). En el filtro ACTOR_ACCOUNT_ID, esto significa que un patrón débil puede coincidir con más usuarios de los previstos.
Si PRs no confiables se construyen en un proyecto que tiene permisos de rol privilegiados en AWS o credenciales de GitHub, esto puede convertirse en un compromiso de la cadena de suministro completo.
Wiz mostró una cadena práctica donde:
- Una allowlist de actores de webhook usó una regex sin anclar.
- Un atacante registró un ID de GitHub que coincidía como superstring de un ID confiable.
- Un PR malicioso activó CodeBuild.
- La ejecución de código en el build se usó para volcar memoria y recuperar credenciales/tokens del proveedor de código fuente.
Misconfiguraciones que permiten la ejecución de código de PR externos
Las siguientes son fallas de alto riesgo y cómo los atacantes abusan de cada una:
EVENTfilters allow untrusted triggers
- Eventos riesgosos comunes:
PULL_REQUEST_CREATED,PULL_REQUEST_UPDATED,PULL_REQUEST_REOPENED. - Otros eventos que también pueden volverse peligrosos si están ligados a builds privilegiados:
PUSH,PULL_REQUEST_CLOSED,PULL_REQUEST_MERGED,RELEASED,PRERELEASED,WORKFLOW_JOB_QUEUED. - Malo:
EVENT="PUSH, PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED"en un proyecto privilegiado. - Mejor: usar aprobación por comentario en PR y minimizar los eventos que disparan builds en proyectos privilegiados.
- Abuso: el atacante abre/actualiza un PR o hace push a una rama que controla, y su código se ejecuta en CodeBuild.
ACTOR_ACCOUNT_IDregex is weak
- Malo: patrones sin anclar como
123456|7890123. - Mejor: anclado con coincidencia exacta
^(123456|7890123)$. - Abuso: una regex demasiado permisiva permite que IDs de GitHub no autorizados pasen las allowlists.
- Other regex filters are weak or missing
HEAD_REF- Malo:
refs/heads/.* - Mejor:
^refs/heads/main$(o una lista explícita de ramas de confianza)
- Malo:
BASE_REF- Malo:
.* - Mejor:
^refs/heads/main$
- Malo:
FILE_PATH- Malo: sin restricciones de paths
- Mejor: excluir archivos riesgosos como
^buildspec\\.yml$,^\\.github/workflows/.*,(^|/)package(-lock)?\\.json$
COMMIT_MESSAGE- Malo: marcador de confianza con coincidencia laxa como
trusted - Mejor: no usar el mensaje de commit como límite de confianza para la ejecución de PRs
- Malo: marcador de confianza con coincidencia laxa como
REPOSITORY_NAME/ORGANIZATION_NAME- Malo:
.*en webhooks de org/global - Mejor: coincidencias exactas solo para repos/org de confianza
- Malo:
WORKFLOW_NAME- Malo:
.* - Mejor: coincidencias del nombre de workflow exactas (o evitar usar esto como control de confianza)
- Malo:
- Abuso: el atacante confecciona ref/path/message/repo para satisfacer una regex permisiva y disparar builds.
excludeMatchedPatternis misused
- Configurar este flag incorrectamente puede invertir la lógica prevista.
- Malo:
FILE_PATH '^buildspec\\.yml$'conexcludeMatchedPattern=falsecuando la intención era bloquear ediciones en buildspec. - Mejor: mismo patrón con
excludeMatchedPattern=truepara negar builds que toquenbuildspec.yml. - Abuso: los defensores creen que niegan eventos/rutas/actores riesgosos, pero en realidad los permiten.
- Multiple
filterGroupscreate accidental bypasses
- CodeBuild evalúa grupos como OR (sufre con que un grupo pase).
- Malo: un grupo estricto + un grupo de respaldo permisivo (p. ej., solo
EVENT=PULL_REQUEST_UPDATED). - Mejor: eliminar grupos de respaldo que no impongan restricciones de actor/ref/path.
- Abuso: el atacante solo necesita satisfacer el grupo más débil.
- Comment approval gate disabled or too permissive
pullRequestBuildPolicy.requiresCommentApproval=DISABLEDes lo menos seguro.- Roles de aprobador excesivamente amplios reducen el control.
- Malo:
requiresCommentApproval=DISABLED. - Mejor:
ALL_PULL_REQUESTSoFORK_PULL_REQUESTScon roles de aprobador mínimos. - Abuso: PRs desde forks/drive-by se ejecutan automáticamente sin la aprobación de mantenedores de confianza.
- No restrictive branch/path strategy for PR builds
- Falta de defensa en profundidad con
HEAD_REF+BASE_REF+FILE_PATH. - Malo: solo
EVENT+ACTOR_ACCOUNT_ID, sin controles de ref/path. - Mejor: combinar restricciones exactas de
ACTOR_ACCOUNT_ID+BASE_REF+HEAD_REF+FILE_PATH. - Abuso: el atacante modifica entradas del build (buildspec/CI/dependencies) y obtiene arbitrary command execution.
- Public visibility + status URL exposure
- URLs públicas de build/check facilitan el reconocimiento por parte del atacante y pruebas iterativas.
- Malo:
projectVisibility=PUBLIC_READcon logs/config sensibles en builds públicos. - Mejor: mantener los proyectos privados salvo que exista una necesidad de negocio fuerte, y sanear logs/artifacts.
- Abuso: el atacante descubre patrones/comportamiento del proyecto y luego ajusta payloads e intentos de bypass.
Token leakage from memory
El write-up de Wiz explica que las credenciales del proveedor de código están presentes en el contexto de runtime del build y pueden ser robadas tras la compromisión del build (por ejemplo, mediante volcado de memoria), lo que permite la toma de control del repositorio si los scopes son amplios.
AWS introdujo hardening después de la divulgación, pero la lección central sigue siendo: never execute untrusted PR code in privileged build contexts y asumir que el código de build controlado por un atacante intentará el robo de credenciales.
Para técnicas adicionales de robo de credenciales en CodeBuild, revisa también:
Finding CodeBuild URLs in GitHub PRs
Si CodeBuild informa el estado de commits de vuelta a GitHub, la URL del build de CodeBuild normalmente aparece en:
- PR page -> Checks tab (o la línea de estado en Conversation/Commits).
- Commit page -> sección de estado/checks -> enlace Details.
- PR commits list -> haz clic en el contexto del check adjunto a un commit.
Para proyectos públicos, este enlace puede exponer metadata/configuración del build a usuarios no autenticados.
Script: detectar URLs de CodeBuild en un PR y comprobar si parecen públicas
```bash #!/usr/bin/env bash set -euo pipefailUsage:
./check_pr_codebuild_urls.sh <pr_number>
Requirements: gh, jq, curl
OWNER=“${1:?owner}” REPO=“${2:?repo}” PR=“${3:?pr_number}”
for bin in gh jq curl timeout; do command -v “$bin” >/dev/null || { echo “[!] Missing dependency: $bin” >&2; exit 1; } done
tmp_commits=“$(mktemp)” tmp_urls=“$(mktemp)” trap ‘rm -f “$tmp_commits” “$tmp_urls”’ EXIT
gh_api() { timeout 20s gh api “$@” 2>/dev/null || true }
Get all commit SHAs in the PR (bounded call to avoid hangs)
gh_api “repos/${OWNER}/${REPO}/pulls/${PR}/commits” –paginate –jq ‘.[].sha’ > “$tmp_commits” if [ ! -s “$tmp_commits” ]; then echo “[!] No commits found (or API call timed out/failed).” >&2 exit 1 fi
echo “[*] PR commits:” cat “$tmp_commits” echo
echo “[*] Searching commit statuses/check-runs for CodeBuild URLs…”
while IFS= read -r sha; do [ -z “$sha” ] && continue
Classic commit statuses (target_url)
gh_api “repos/${OWNER}/${REPO}/commits/${sha}/status”
–jq ‘.statuses[]? | .target_url // empty’ 2>/dev/null || true
GitHub Checks API (details_url)
gh_api “repos/${OWNER}/${REPO}/commits/${sha}/check-runs”
–jq ‘.check_runs[]? | .details_url // empty’ 2>/dev/null || true
done < “$tmp_commits” | sort -u > “$tmp_urls”
grep -Ei ‘codebuild|codebuild.aws.amazon.com|console.aws.amazon.com/.*/codebuild’ “$tmp_urls” || true
echo echo “[*] Public-access heuristic:” echo “ - If URL redirects to signin.aws.amazon.com -> likely not public“ echo “ - If URL is directly reachable (HTTP 200) without auth redirect -> potentially public“ echo
cb_urls=“$(grep -Ei ‘codebuild|codebuild.aws.amazon.com|console.aws.amazon.com/./codebuild’ “$tmp_urls” || true)“ if [ -z “$cb_urls” ]; then echo “[] No CodeBuild URLs found in PR statuses/check-runs.” exit 0 fi
while IFS= read -r url; do [ -z “$url” ] && continue final_url=“$(timeout 20s curl -4 -sS -L –connect-timeout 5 –max-time 20 -o /dev/null -w ‘%{url_effective}’ “$url” || true)“ code=“$(timeout 20s curl -4 -sS -L –connect-timeout 5 –max-time 20 -o /dev/null -w ‘%{http_code}’ “$url” || true)“
if echo “$final_url” | grep -qi ‘signin.aws.amazon.com’; then verdict=“NOT_PUBLIC_OR_AUTH_REQUIRED” elif [ “$code” = “200” ]; then verdict=“POTENTIALLY_PUBLIC” else verdict=“UNKNOWN_CHECK_MANUALLY” fi
printf ‘%s\t%s\t%s\n’ “$verdict” “$code” “$url” done <<< “$cb_urls”
Probado con:
```bash
bash /tmp/check_pr_codebuild_urls.sh carlospolop codebuild-codebreach-ctf-lab 1
Lista de verificación rápida de auditoría
# Enumerate projects
aws codebuild list-projects
# Inspect source/webhook configuration
aws codebuild batch-get-projects --names <project-name>
# Inspect global source credentials configured in account
aws codebuild list-source-credentials
Revise cada proyecto en busca de:
webhook.filterGroupsque contengan eventos PR.- patrones de
ACTOR_ACCOUNT_IDque no estén anclados con^...$. pullRequestBuildPolicy.requiresCommentApprovaligual aDISABLED.- Falta de restricciones de rama/ruta.
serviceRolede altos privilegios.- Ámbito y reutilización arriesgados de credenciales de origen.
Guía de endurecimiento
- Requerir aprobación por comentario para builds de PR (
ALL_PULL_REQUESTSoFORK_PULL_REQUESTS). - Si usa listas de permitidos (allowlists) de actores, ancle las expresiones regulares y manténgalas exactas.
- Agregue restricciones
FILE_PATHpara evitar ediciones no confiables enbuildspec.ymly en scripts de CI. - Separe los builds de release confiables de los builds de PR no confiables en proyectos/roles distintos.
- Use tokens de proveedor de origen de granularidad fina y con el mínimo privilegio (prefiera identidades dedicadas de bajo privilegio).
- Audite continuamente los filtros de webhook y el uso de credenciales de origen.
Referencias
- Wiz: CodeBreach - AWS CodeBuild ACTOR_ID regex bypass and token theft
- AWS CodeBuild API - WebhookFilter
- AWS CLI - codebuild create-webhook
- AWS CodeBuild User Guide - Best practices for webhooks
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
HackTricks Cloud

