AWS CodeBuild - Untrusted PR Webhook Bypass (CodeBreach-style)
Tip
学习并练习 AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学习并练习 GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学习并练习 Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 subscription plans!
- 加入 💬 Discord group 或者 telegram group 或 关注 我们的 Twitter 🐦 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud github 仓库 提交 PRs 来分享 hacking tricks。
当一个面向公众的 PR 工作流 连接到具有弱 webhook 控制的 特权 CodeBuild 项目 时,会出现这种攻击向量。
如果外部攻击者能让 CodeBuild 执行他们的 pull request,通常可以在构建过程中获得 任意代码执行(构建脚本、依赖钩子、测试脚本等),然后横向攻击以获取 secrets、IAM 凭证或源提供商凭证。
Why this is dangerous
CodeBuild 的 webhook 过滤器(对于非 EVENT 过滤器)使用 regex 模式进行评估。在 ACTOR_ACCOUNT_ID 过滤器中,这意味着弱模式可能匹配比预期更多的用户。
如果在具有特权 AWS 角色权限或 GitHub 凭证的项目中构建不受信任的 PR,这可能演变为完整的供应链妥协。
Wiz 展示了一个实际的链条,其中:
- 一个 webhook actor allowlist 使用了 未加锚点的 regex。
- 攻击者注册了一个 GitHub ID,作为受信任 ID 的 superstring 被匹配。
- 一个恶意 PR 触发了 CodeBuild。
- 构建中的代码执行被用来转储内存并恢复源提供商凭证/令牌。
Misconfigurations that allow external PR code execution
下面是高风险的错误以及攻击者如何滥用每一种:
EVENTfilters allow untrusted triggers
- 常见的高风险事件:
PULL_REQUEST_CREATED,PULL_REQUEST_UPDATED,PULL_REQUEST_REOPENED. - 其他如果与特权构建关联也可能变得危险的事件:
PUSH,PULL_REQUEST_CLOSED,PULL_REQUEST_MERGED,RELEASED,PRERELEASED,WORKFLOW_JOB_QUEUED. - 不良示例:在特权项目中使用
EVENT="PUSH, PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED"。 - 更好:对特权项目使用 PR 评论审批并尽量减少触发事件。
- 滥用:攻击者打开/更新 PR 或向其控制的分支 push,他们的代码在 CodeBuild 中执行。
ACTOR_ACCOUNT_IDregex is weak
- 不良示例:像
123456|7890123这样的未锚定模式。 - 更好:使用精确匹配锚定
^(123456|7890123)$。 - 滥用:regex 过度匹配允许未授权的 GitHub ID 通过允许列表。
- Other regex filters are weak or missing
HEAD_REF- 不良示例:
refs/heads/.* - 更好:
^refs/heads/main$(或显式的受信任列表)
- 不良示例:
BASE_REF- 不良示例:
.* - 更好:
^refs/heads/main$
- 不良示例:
FILE_PATH- 不良示例:没有路径限制
- 更好:排除高风险文件,例如
^buildspec\\.yml$,^\\.github/workflows/.*,(^|/)package(-lock)?\\.json$
COMMIT_MESSAGE- 不良示例:像
trusted这样宽松匹配的信任标记 - 更好:不要将提交信息用作 PR 执行的信任边界
- 不良示例:像
REPOSITORY_NAME/ORGANIZATION_NAME- 不良示例:在 org/全局 webhook 中使用
.* - 更好:仅精确匹配仓库/组织
- 不良示例:在 org/全局 webhook 中使用
WORKFLOW_NAME- 不良示例:
.* - 更好:仅精确的 workflow 名称匹配(或避免将其作为信任控制)
- 不良示例:
- 滥用:攻击者构造 ref/路径/提交信息/仓库上下文以满足宽松的 regex 并触发构建。
excludeMatchedPatternis misused
- 错误设置此标志可能会将意图逻辑反转。
- 不良示例:使用
FILE_PATH '^buildspec\\.yml$'并将excludeMatchedPattern=false,而本意是阻止对 buildspec 的更改。 - 更好:对同一模式使用
excludeMatchedPattern=true来拒绝触及buildspec.yml的构建。 - 滥用:防御者以为他们阻止了高风险事件/路径/actor,实际上却允许了。
- Multiple
filterGroupscreate accidental bypasses
- CodeBuild 将组作为 OR 进行评估(通过任一组即可)。
- 不良示例:一个严格组 + 一个宽松的回退组(例如只有
EVENT=PULL_REQUEST_UPDATED)。 - 更好:移除不强制 actor/ref/path 约束的回退组。
- 滥用:攻击者只需满足最弱的组。
- Comment approval gate disabled or too permissive
pullRequestBuildPolicy.requiresCommentApproval=DISABLED是最不安全的。- 过于宽泛的批准者角色会降低控制力度。
- 不良示例:
requiresCommentApproval=DISABLED。 - 更好:使用
ALL_PULL_REQUESTS或FORK_PULL_REQUESTS并限制批准者角色。 - 滥用:fork/drive-by PR 自动运行,无需受信任维护者批准。
- No restrictive branch/path strategy for PR builds
- 缺少通过
HEAD_REF+BASE_REF+FILE_PATH的纵深防御。 - 不良示例:只有
EVENT+ACTOR_ACCOUNT_ID,没有 ref/path 控制。 - 更好:结合精确的
ACTOR_ACCOUNT_ID+BASE_REF+HEAD_REF+FILE_PATH限制。 - 滥用:攻击者修改构建输入(buildspec/CI/依赖)并获得任意命令执行。
- Public visibility + status URL exposure
- 公开的构建/检查 URL 提高了攻击者的侦察和迭代测试能力。
- 不良示例:
projectVisibility=PUBLIC_READ,且在公开构建中有敏感日志/配置。 - 更好:除非有强烈的业务需求,否则保持项目私有,并对日志/构件进行清理。
- 滥用:攻击者发现项目模式/行为,然后调整有效载荷和绕过尝试。
Token leakage from memory
Wiz 的报告解释了源提供商凭证存在于构建运行时上下文中,并且在构建被攻破后可以被窃取(例如通过 memory dumping),如果权限范围过大则可导致仓库接管。
AWS 在漏洞披露后引入了加固,但核心教训依然是:永远不要在特权构建上下文中执行不受信任的 PR 代码,并假定攻击者控制的构建代码会尝试窃取凭证。
For additional credential theft techniques in CodeBuild, also check:
Finding CodeBuild URLs in GitHub PRs
如果 CodeBuild 将提交状态报告回 GitHub,CodeBuild 构建 URL 通常出现在:
- PR 页面 -> Checks 选项卡(或 Conversation/Commits 中的状态行)。
- Commit 页面 -> 状态/检查部分 -> Details 链接。
- PR commits 列表 -> 点击附加在提交上的检查上下文。
对于公共项目,该链接可能会向未认证用户暴露构建元数据/配置。
脚本:在 PR 中检测 CodeBuild URL 并测试它们是否看起来是公开的
```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”
已在以下环境测试通过:
```bash
bash /tmp/check_pr_codebuild_urls.sh carlospolop codebuild-codebreach-ctf-lab 1
快速审计检查表
# 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
检查每个项目是否存在:
webhook.filterGroupscontaining PR events.ACTOR_ACCOUNT_IDpatterns that are not anchored with^...$.pullRequestBuildPolicy.requiresCommentApprovalequal toDISABLED.- Missing branch/path restrictions.
- High-privilege
serviceRole. - Risky source credentials scope and reuse.
加固建议
- 要求 PR 构建的评论审批(
ALL_PULL_REQUESTS或FORK_PULL_REQUESTS)。 - If using actor allowlists,锚定正则并保持精确匹配。
- Add
FILE_PATHrestrictions to avoid untrusted edits tobuildspec.ymland CI scripts. - 将受信任的发布构建与不受信任的 PR 构建分离到不同的项目/角色。
- Use fine-grained, least-privileged source-provider tokens(prefer dedicated low-privilege identities)。
- 持续审计 webhook filters 和 source credential 的使用。
References
- 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
学习并练习 AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学习并练习 GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学习并练习 Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 subscription plans!
- 加入 💬 Discord group 或者 telegram group 或 关注 我们的 Twitter 🐦 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud github 仓库 提交 PRs 来分享 hacking tricks。
HackTricks Cloud

