# AWS CodeBuild - Untrusted PR Webhook Bypass (CodeBreach-style)

{{#include ../../../../banners/hacktricks-training.md}}

Questo vettore di attacco si presenta quando un workflow PR esposto pubblicamente è collegato a un progetto CodeBuild privilegiato con controlli webhook deboli.

Se un attacker esterno riesce a far eseguire a CodeBuild la loro pull request, di solito può ottenere l'esecuzione di codice arbitrario all'interno della build (script di build, hook delle dipendenze, script di test, ecc.), e poi pivotare verso secrets, credenziali IAM o credenziali del provider di sorgente.

## Why this is dangerous

I filtro webhook di CodeBuild sono valutati con pattern regex (per i filtri diversi da `EVENT`). Nel filtro `ACTOR_ACCOUNT_ID`, questo significa che un pattern debole può corrispondere a più utenti del previsto.
Se PR non attendibili vengono costruite in un progetto che ha permessi role AWS privilegiati o credenziali GitHub, questo può diventare una compromissione completa della supply-chain.

Wiz ha mostrato una catena pratica dove:

1. Una allowlist di actor del webhook usava una **regex non ancorata**.
2. Un attacker ha registrato un ID GitHub che corrispondeva come **superstringa** di un ID trusted.
3. Una PR malevola ha triggerato CodeBuild.
4. L'esecuzione del codice nella build è stata usata per dumpare memoria e recuperare credenziali/token del provider di sorgente.

## Misconfigurations that allow external PR code execution

Di seguito gli errori ad alto rischio e come gli attacker abusano di ciascuno:

1. **`EVENT` filters allow untrusted triggers**
- Eventi comunemente rischiosi: `PULL_REQUEST_CREATED`, `PULL_REQUEST_UPDATED`, `PULL_REQUEST_REOPENED`.
- Altri eventi che possono diventare pericolosi se collegati a build privilegiate: `PUSH`, `PULL_REQUEST_CLOSED`, `PULL_REQUEST_MERGED`, `RELEASED`, `PRERELEASED`, `WORKFLOW_JOB_QUEUED`.
- Pericoloso: `EVENT="PUSH, PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED"` in un progetto privilegiato.
- Consigliato: usare approvazione tramite commento su PR e minimizzare gli eventi di trigger per i progetti privilegiati.
- Abuso: l'attacker apre/aggiorna una PR o push su un branch che controlla, e il proprio codice viene eseguito in CodeBuild.

2. **`ACTOR_ACCOUNT_ID` regex is weak**
- Pericoloso: pattern non ancorati come `123456|7890123`.
- Consigliato: ancorare con corrispondenza esatta `^(123456|7890123)$`.
- Abuso: l'over-match della regex permette a ID GitHub non autorizzati di passare le allowlist.

3. **Other regex filters are weak or missing**
- `HEAD_REF`
  - Pericoloso: `refs/heads/.*`
  - Consigliato: `^refs/heads/main$` (o una lista esplicita di branch trusted)
- `BASE_REF`
  - Pericoloso: `.*`
  - Consigliato: `^refs/heads/main$`
- `FILE_PATH`
  - Pericoloso: nessuna restrizione sui percorsi
  - Consigliato: escludere file rischiosi come `^buildspec\\.yml$`, `^\\.github/workflows/.*`, `(^|/)package(-lock)?\\.json$`
- `COMMIT_MESSAGE`
  - Pericoloso: fidarsi di un marcatore nel commit con match permissivo come `trusted`
  - Consigliato: non usare il commit message come confine di trust per l'esecuzione delle PR
- `REPOSITORY_NAME` / `ORGANIZATION_NAME`
  - Pericoloso: `.*` in webhook a livello org/globale
  - Consigliato: corrispondenze esatte solo per repo/org
- `WORKFLOW_NAME`
  - Pericoloso: `.*`
  - Consigliato: corrispondenze esatte del nome del workflow (o evitare di usare questo come meccanismo di trust)
- Abuso: l'attacker costruisce ref/path/message/context del repo in modo da soddisfare una regex permissiva e triggerare le build.

4. **`excludeMatchedPattern` is misused**
- Impostare questo flag in modo errato può invertire la logica desiderata.
- Pericoloso: `FILE_PATH '^buildspec\\.yml$'` con `excludeMatchedPattern=false` quando l'intento era bloccare modifiche a buildspec.
- Consigliato: stesso pattern con `excludeMatchedPattern=true` per negare build che toccano `buildspec.yml`.
- Abuso: i defender pensano di negare eventi/percorsi/actor rischiosi, ma in realtà li consentono.

5. **Multiple `filterGroups` create accidental bypasses**
- CodeBuild valuta i gruppi come OR (basta che un gruppo passi).
- Pericoloso: un gruppo rigido + un gruppo fallback permissivo (es., solo `EVENT=PULL_REQUEST_UPDATED`).
- Consigliato: rimuovere gruppi fallback che non applicano vincoli su actor/ref/path.
- Abuso: l'attacker ha bisogno solo di soddisfare il gruppo più debole.

6. **Comment approval gate disabled or too permissive**
- `pullRequestBuildPolicy.requiresCommentApproval=DISABLED` è il meno sicuro.
- Ruoli approvatori troppo estesi riducono il controllo.
- Pericoloso: `requiresCommentApproval=DISABLED`.
- Consigliato: `ALL_PULL_REQUESTS` o `FORK_PULL_REQUESTS` con ruoli approvatori ristretti.
- Abuso: PR da fork/drive-by eseguono automaticamente senza approvazione di maintainer trusted.

7. **No restrictive branch/path strategy for PR builds**
- Mancanza di defense-in-depth con `HEAD_REF` + `BASE_REF` + `FILE_PATH`.
- Pericoloso: solo `EVENT` + `ACTOR_ACCOUNT_ID`, senza controlli su ref/path.
- Consigliato: combinare `ACTOR_ACCOUNT_ID` esatto + `BASE_REF` + `HEAD_REF` + restrizioni `FILE_PATH`.
- Abuso: l'attacker modifica input di build (buildspec/CI/dipendenze) e ottiene esecuzione di comandi arbitrari.

8. **Public visibility + status URL exposure**
- URL di build/check pubblici facilitano il ricon e i test iterativi dell'attacker.
- Pericoloso: `projectVisibility=PUBLIC_READ` con log/config sensibili in build pubbliche.
- Consigliato: mantenere i progetti privati a meno di forti necessità business, e sanitizzare log/artifact.
- Abuso: l'attacker scopre pattern/comportamento del progetto e poi affina payload e tentativi di bypass.

## Token leakage from memory

La write-up di Wiz spiega che le credenziali del provider di sorgente sono presenti nel contesto di runtime della build e possono essere rubate dopo una compromissione della build (per esempio tramite memory dumping), permettendo il takeover del repository se gli scope sono ampi.

AWS ha introdotto hardening dopo la disclosure, ma la lezione principale rimane: **non eseguire codice di PR non attendibili in contesti di build privilegiati** e assumere che codice controllato dall'attacker tenterà di rubare credenziali.

Per tecniche aggiuntive di credential theft in CodeBuild, consulta anche:

{{#ref}}
aws-codebuild-token-leakage.md
{{#endref}}

## Finding CodeBuild URLs in GitHub PRs

Se CodeBuild riporta lo stato back a GitHub, l'URL della build di CodeBuild di solito appare in:

1. **PR page** -> **Checks** tab (o la linea di stato in Conversation/Commits).
2. **Commit page** -> sezione status/checks -> link **Details**.
3. **PR commits list** -> cliccare il contesto di check allegato a un commit.

Per progetti pubblici, questo link può esporre metadata/configurazione della build ad utenti non autenticati.

<details>
<summary>Script: rileva URL CodeBuild in una PR e verifica se appaiono pubblici</summary>
```bash
#!/usr/bin/env bash
set -euo pipefail

# Usage:
#   ./check_pr_codebuild_urls.sh <owner> <repo> <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"
```
Testato con:
```bash
bash /tmp/check_pr_codebuild_urls.sh carlospolop codebuild-codebreach-ctf-lab 1
```
</details>

## Checklist rapida di audit
```bash
# 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
```
Controlla ogni progetto per:

- `webhook.filterGroups` containing PR events.
- `ACTOR_ACCOUNT_ID` patterns that are not anchored with `^...$`.
- `pullRequestBuildPolicy.requiresCommentApproval` equal to `DISABLED`.
- Assenza di restrizioni su branch/percorso.
- `serviceRole` ad alto privilegio.
- Ambito e riuso rischiosi delle source credentials.

## Linee guida di hardening

1. Richiedi approvazione via commento per le build PR (`ALL_PULL_REQUESTS` o `FORK_PULL_REQUESTS`).
2. Se usi allowlist di actor, ancora le regex e mantienile esatte.
3. Aggiungi restrizioni `FILE_PATH` per evitare modifiche non attendibili a `buildspec.yml` e script CI.
4. Separa le build di release affidabili dalle build PR non affidabili in progetti/ruoli separati.
5. Usa token del source-provider a granularità fine e con privilegi minimi (preferisci identità dedicate a basso privilegio).
6. Monitora continuamente i filtri webhook e l'uso delle credenziali sorgenti.

## Riferimenti

- [Wiz: CodeBreach - AWS CodeBuild ACTOR_ID regex bypass and token theft](https://www.wiz.io/blog/wiz-research-codebreach-vulnerability-aws-codebuild)
- [AWS CodeBuild API - WebhookFilter](https://docs.aws.amazon.com/codebuild/latest/APIReference/API_WebhookFilter.html)
- [AWS CLI - codebuild create-webhook](https://docs.aws.amazon.com/cli/latest/reference/codebuild/create-webhook.html)
- [AWS CodeBuild User Guide - Best practices for webhooks](https://docs.aws.amazon.com/codebuild/latest/userguide/webhooks.html)

{{#include ../../../../banners/hacktricks-training.md}}
