Table of Contents

In July 2025, AWS disclosed that a threat actor had stolen source repository access tokens by dumping the memory of a CodeBuild build environment. A malicious pull request was enough. When the build ran, it read the token out of process memory and exfiltrated it, and the attacker used it to reach the repositories behind the AWS Toolkit for Visual Studio Code and the AWS SDK for .NET. We covered the incident and the technique in Lessons from AWS CodeBuild's Memory-Dump Incident (CVE-2025-8217).

That is the environment more and more teams are now pointing their GitHub Actions jobs at. AWS CodeBuild can register itself as a just-in-time GitHub Actions runner, so a job that used to run on ubuntu-latest runs inside your AWS account instead, on your compute, in your VPC, under your IAM role.

Harden-Runner now supports those runners.

What is supported

Harden-Runner supports GitHub Actions runners hosted on AWS CodeBuild on EC2 compute, starting with the Harden-Runner GitHub Action v2.20.1. v2.21.0 extends that to CodeBuild runners running Linux containers on EC2 compute, which covers the custom image scenario.

Two CodeBuild project settings matter, and both are configured on the project rather than in your workflow:

CodeBuild setting Required value
Compute EC2 Lambda compute is not supported
Host kernel kernel-6 (Amazon Linux 2023)
Privileged Enabled
Provisioning model
On-demandReserved capacity
Both are supported.
Environment image
Managed image with Running mode set to Instance
or
Custom image with Environment type set to Linux Container

Host kernel is a relatively new CodeBuild setting, and it is the one most likely to trip you up, because the agent needs kernel-level features that kernel-6 provides. Privileged mode is required for the same reason.

Privileged and Host kernel are set in the CodeBuild project's Additional configuration panel.

Once the project is configured, integration is the same one-step pattern used on GitHub-hosted runners. Add the action as the first step of the job.

jobs:
  build:
    runs-on: codebuild-my-project-${{ github.run_id }}-${{ github.run_attempt }}

    steps:
      - uses: step-security/harden-runner@v2.21.0
        with:
          egress-policy: audit

      - uses: actions/checkout@v4

      # ... rest of your job

The runs-on label is the standard CodeBuild runner label:

codebuild-<project-name>-${{ github.run_id }}-${{ github.run_attempt }}, where the project name matches the CodeBuild project whose webhook is configured for WORKFLOW_JOB_QUEUED events. No buildspec or webhook changes are needed.

For custom images, select the image on the project with Environment type set to Linux Container, or use CodeBuild's image:custom-<environment-type>-<custom-image-identifier> label override. Custom images from Amazon ECR and from external Docker registries both work. Custom images require Harden-Runner v2.21.0 or later.

Why this matters more on CodeBuild than on a hosted runner

On a GitHub-hosted runner, a compromised job holds whatever secrets you passed into it. On a CodeBuild-hosted runner, it holds those plus the identity of the build environment itself.

CodeBuild runners assume an IAM service role. That is the point of using them: you stop putting long-lived AWS credentials in GitHub secrets and let the role handle access instead. It is also why the blast radius is different. A malicious dependency that lands in a CodeBuild-hosted job inherits that role, and if the project runs in a VPC, it inherits network reachability to whatever is in those subnets. Internal registries, internal APIs, databases, metadata endpoints.

None of that is visible to GitHub. The job log shows you what the build printed. It does not show you that step four opened a connection to an internal host it has never contacted before, or that a process read the memory of the runner worker.

Harden-Runner sees both. Outbound network calls, file writes, and process executions are captured on the runner and correlated to the exact workflow step that caused them. The memory-read technique behind CVE-2025-8217 is the same technique used against GitHub Actions in the tj-actions/changed-files compromise, and Harden-Runner raises it as a runtime detection with a triage runbook attached.

Credential theft out of CI is not a hypothetical pattern either. In the Team PCP campaign, CloudSEK's disclosure put 78,330 secrets taken from the pipelines of 2,186 organizations in five days. Pipelines are where the credentials are.

One fleet, one view

Most organizations running CodeBuild runners are not running only CodeBuild runners. There are GitHub-hosted jobs, maybe an ARC cluster, maybe self-hosted VMs, and now CodeBuild for the jobs that need to sit inside AWS.

Harden-Runner treats that as one fleet. The same detections, the same baselines, the same policies from the Policy Store, and the same dashboard, whatever the runs-on label says. That consistency is why 13,000+ open-source projects and enterprises run Harden-Runner.

Setup details for every supported runner environment are in the Harden-Runner documentation.

Harden-Runner is open source. Add it to your workflows today, on GitHub-hosted, self-hosted, or CodeBuild-hosted runners. View Harden-Runner on GitHub

Not sure which of your workflows are unmonitored? Run a free GitHub Actions Audit across your organization.

Running GitHub Actions on AWS CodeBuild? See how Harden-Runner secures your whole runner fleet. Start free or request a demo.

Explore Related Posts