CodeBreach: Two Missing Regex Characters Nearly Handed Attackers the Keys to AWS's Own GitHub Repos
A webhook filter missing two regex anchor characters let researchers predict a trusted GitHub actor ID and hijack AWS's own CodeBuild pipelines, gaining admin access to repos like aws-sdk-js-v3. No CVE, no exploit code, just patient bot-account math.
The conventional wisdom in CI/CD security is that GitHub Actions is the reckless teenager and AWS CodeBuild, with its VPC isolation, IAM roles, and enterprise-grade access controls, is the responsible adult in the room. AWS's own GitHub repositories just proved that wisdom wrong. For over a year, a misconfiguration in CodeBuild's GitHub integration meant that anyone patient enough to do some regex math and register a few hundred throwaway bot accounts could have walked away with admin credentials to aws-sdk-js-v3, the JavaScript SDK that a large chunk of the internet's AWS-connected applications quietly depend on.
Wiz Research named it CodeBreach, disclosed it to AWS on August 25, 2025, and AWS shipped a fix the following month. The public advisory only landed in January 2026, which is roughly the pace I'd expect for a bug this embarrassing to a cloud provider that builds its entire brand on being the trustworthy one. I've spent enough years around CI/CD pipelines feeding production deploys to know exactly why this class of bug keeps recurring, and exactly why it's so hard to catch in a design review. This one deserves a proper walkthrough.
What Wiz Actually Found
AWS CodeBuild can connect directly to a GitHub repository and trigger builds automatically on events like pull requests. Because letting any fork or any contributor trigger a privileged build is an obviously bad idea, AWS gives you webhook filters: rules that decide which events are even allowed to kick off a build. One of the filter types matches on ACTOR_ID — the numeric GitHub or GitHub Enterprise Server account ID of whoever triggered the event — using a regular expression. The idea is simple: only let builds fire when the actor ID matches a trusted maintainer.
Four AWS-managed open source projects used exactly this setup to gate builds on pull requests:
aws-sdk-js-v3aws-lcamazon-corretto-crypto-providerawslabs/open-data-registry
And all four had the same fatal flaw: their regex patterns didn't anchor the match with ^ and $. Without those two characters, a regex that's supposed to say "this string is 755743" instead says "this string contains 755743 somewhere." A trusted six-digit maintainer ID like 755743 would happily match against an attacker-controlled ID of 226755743, because 755743 is sitting right there as a substring. That's the entire vulnerability. Not a memory corruption bug, not an auth bypass in the traditional sense — just a regex that forgot to say "exactly this and nothing else."
On its own, that's a bad but low-severity bug: an attacker would need to control a GitHub account whose numeric ID happens to contain the trusted ID as a substring, and account IDs aren't something you get to pick. Wiz's actual contribution was realizing that GitHub hands out account IDs sequentially, which turns "happens to contain" into "can be engineered on a schedule."
The Kill Chain
Here's how Wiz researchers Yuval Avrahami and Nir Ohfeld turned an unanchored regex into a credential-theft primitive against AWS's own infrastructure.
- Identify the trusted actor ID. The CodeBuild webhook filter for
aws-sdk-js-v3was configured to trust a specific maintainer account, a relatively "old" GitHub account with a six-digit numeric ID such as755743. This ID isn't secret — GitHub exposes account IDs through its public API. - Watch GitHub's ID counter. New GitHub accounts get IDs assigned in strict ascending order. At the time of the research, new signups were landing in the nine-digit range. That means every new account's ID starts with a leading digit followed by eight more, and sooner or later that nine-digit sequence will contain the target's six-digit ID as a substring.
- Force the eclipse. Instead of waiting around for a natural signup to line up, Wiz used GitHub Apps to mass-produce accounts on demand. Every time you create a GitHub App, GitHub auto-creates a corresponding bot user with a fresh, sequential ID. By scripting hundreds of app creations in a row, Wiz could walk the ID counter forward deliberately and predict, to within about five days, exactly when a bot ID containing the target's six digits would be minted.
- Trigger the build as the forged actor. Once an ID like
226755743existed, opening a pull request (or triggering whatever event the filter watched) as that account satisfied the unanchored regex. CodeBuild had no way to tell the difference between the real trusted maintainer and a nine-digit bot account that merely contained the same digits. - Harvest the credentials. The build fired with its normal privileges intact — including a Personal Access Token belonging to
aws-sdk-js-automation, a service account with full admin rights over the repository. That token was reachable from inside the build environment. - Cash it in. With that PAT in hand, an attacker could push commits directly to
main, self-approve pull requests, rotate branch protections, and pull repository secrets — everything needed to slip a backdoor into a package that ends up in thousands of downstreamnpm installruns.

Figure 1: How GitHub's sequential account IDs let a six-digit trusted ID get "eclipsed" by a newly minted nine-digit account, defeating an unanchored regex filter. (Source: Wiz Research)
What makes this genuinely nasty is that none of the individual steps look suspicious in isolation. Registering GitHub Apps isn't rate-limited the way credential stuffing is. Opening a pull request from a new account isn't inherently malicious. The attack lives entirely in the gap between "technically allowed" and "was supposed to be impossible," and that gap only exists because of two missing characters in a regex nobody re-read after it shipped.

Figure 2: The broader pattern of pull-request-triggered attacks against CodeBuild-integrated repositories. (Source: Wiz Research)
Scope and Blast Radius
| Factor | Detail |
|---|---|
| Vulnerability name | CodeBreach (coined by Wiz Research) |
| Affected control | AWS CodeBuild GitHub webhook ACTOR_ID filter |
| Root cause | Unanchored regex (missing ^ / $) allowing substring match on GitHub numeric actor IDs |
| Affected repositories | aws-sdk-js-v3, aws-lc, amazon-corretto-crypto-provider, awslabs/open-data-registry |
| Credential exposed | Personal Access Token of aws-sdk-js-automation with full repo admin rights |
| Disclosure date | August 25, 2025 |
| AWS fix shipped | September 2025 |
| Public advisory | January 2026 (AWS Security Bulletin 2026-002-AWS) |
| Exploitation in the wild | None found, per AWS |
Not an Isolated Incident
This is the third time in about eighteen months that researchers have found the exact same category of flaw sitting in CI/CD trust boundaries between GitHub and a build system. Sysdig previously documented insecure GitHub Actions workflows using pull_request_target that leaked the privileged GITHUB_TOKEN across dozens of open source projects, including ones tied to MITRE and Splunk. A few months after that, Orca Security published a two-part analysis dubbed pull_request_nightmare, showing the same pull_request_target misconfiguration pattern sitting in workflows belonging to Google, Microsoft, NVIDIA, and other Fortune 500 engineering orgs, again allowing arbitrary code execution and secret exfiltration from a single forked pull request.
CodeBreach is a different vendor and a different filter mechanism, but it's the same underlying failure mode: a build system that treats "an event arrived from GitHub that looks like it came from someone trusted" as equivalent to "this really did come from someone trusted." As Wiz put it in their write-up, this is a textbook case of why CI/CD is such an attractive target — a subtle, easily overlooked flaw, combined with untrusted external input and privileged internal credentials, is close to a perfect setup for high-impact breaches that require zero prior access to anything.
My Take
I've built and hardened enough CI/CD pipelines to know that the actor-ID filter here wasn't lazy engineering — it's exactly the kind of control I'd have reached for myself. A regex match on a trusted account ID is a completely reasonable idea on a whiteboard. The problem is that regex is a terrible place to put a security boundary, because regex bugs don't look like security bugs. Nobody doing a code review reads 755743 without anchors and thinks "supply chain risk." They think "yeah, that matches the ID, ship it." The failure is invisible until someone thinks adversarially about what "matches" actually means to a regex engine versus what it means to a human reading it.
The part that should worry infrastructure teams more than the regex itself is the sequential ID trick. It's a reminder that "unpredictable" and "hard to enumerate" are not the same property, and platforms love to treat them as interchangeable. GitHub's numeric account IDs aren't secret and were never designed to be unguessable — they're just large numbers that increment. The moment you build an authorization decision on top of a value like that, you've inherited every property of that value, including the fact that someone with API access and a scripting habit can walk the entire address space forward on a predictable timeline. I've seen the same class of mistake with auto-incrementing database IDs used as authorization tokens, and with sequential invoice or order numbers used as "secret" links. The pattern always looks safe until someone treats it as a target instead of an implementation detail.
I'd also push back gently on the framing that this is "just" a project-specific misconfiguration and not a CodeBuild service issue, which is how AWS characterized it in their bulletin. That's technically accurate, but it undersells the platform's share of the blame. If a security control is this easy to misconfigure into uselessness — one missing pair of characters and the entire filter becomes decorative — the platform should either validate that regex patterns are anchored by default, warn loudly when they aren't, or not offer regex matching for a security-critical field at all. AWS eventually built exactly that kind of stronger primitive with Pull Request Comment Approval and CodeBuild-hosted runners, which tells you they agree, they just got there after the fact.
What You Should Do Right Now
If you have any CodeBuild project wired to GitHub, or any CI system that uses an actor/user identity filter to gate privileged builds, here's the concrete checklist, not "stay vigilant":
- Audit every actor-ID or username regex in your webhook filters today. If it doesn't start with
^and end with$, it's a substring match, not an exact match. Fix it now — this is a five-minute change with a very high payoff. - Don't rely on identity filters alone. Turn on CodeBuild's Pull Request Comment Approval gate so a build from an untrusted contributor requires an explicit human approval, not just a regex match.
- Move to CodeBuild-hosted runners where GitHub Actions workflows themselves manage trigger logic, rather than reproducing trust decisions inside webhook filter configuration that's easy to get subtly wrong and hard to unit test.
- Stop reusing one powerful PAT across a CI system. Generate a unique, narrowly scoped Personal Access Token per CodeBuild project, and never grant repo-admin scope to a token a build environment can read. If a build only needs to check out code and post a status, it doesn't need a token that can push to
main. - Use a dedicated, unprivileged GitHub account for CI integrations instead of automation accounts inheriting admin rights on the underlying repository — the blast radius of a leaked token should be "this repo's CI status," not "this repo's entire history and secrets."
- Never build authorization logic on top of any sequential or otherwise low-entropy identifier — account IDs, database primary keys, order numbers. If you need to distinguish a trusted principal, use signed tokens, mTLS, or platform-native identity assertions that an attacker can't walk toward on a schedule.
- Treat CI/CD credentials in build environment memory as exposed by default. AWS's own remediation included steps to keep GitHub tokens from sitting in memory longer than necessary during a build — do the same audit on your own runners.
This article was researched and drafted with AI assistance as part of an experiment in building a faster tech-writing workflow, then reviewed and edited before publishing.
Primary source: AWS CodeBuild Misconfiguration Exposed GitHub Repos to Potential Supply Chain Attacks — The Hacker News, January 2026
Secondary source: Wiz Research: CodeBreach — A Vulnerability in AWS CodeBuild — Wiz, January 2026
Secondary source: Pull Request Nightmare: GitHub Actions RCE — Orca Security, September 2025
Keep Reading
Deadbugz: The MCP Server That Waits Three Tool Calls Before It Turns Hostile
A GitHub account filed 23 pull requests in 74 minutes, each quietly adding a malicious MCP server. It behaves for exactly three tool calls, then rewrites its own metadata into instructions to hunt SSH keys, AWS credentials, and kubeconfigs.
The BGP Hijack That Rooted Virtualizor Hypervisors in 33 Hours
AS62390 hijacked a Hetzner /24 for 33 hours, used the diversion to mint a real Let's Encrypt certificate, and pushed a backdoored Virtualizor update straight to hypervisor root. Here's how the routing data proves it, step by step.
PoisonedRefresh: The F5 BIG-IP Rootkit That Hides Its Web Shell Where File Scanners Can't See
A Linux rootkit on compromised F5 BIG-IP APM appliances hooks Apache's PHP loader to inject a web shell straight into memory, leaving the on-disk webtop scripts byte-for-byte clean. It's tied to the exploited CVE-2025-53521, and it's a working blueprint for fileless persistence on the access gateways guarding enterprise identity.