LATEST
Verified updates will appear here after publishing begins.
View all updates

CI/CD Runner Compromised: What Secrets, Repositories and Artifacts Are Exposed?

A compromised CI/CD runner can expose much more than one secret. Reconstruct which jobs ran, which credentials materialized, which repositories and

CI/CD runner compromise article hero showing blast radius investigation

Key takeaways

  • A compromised CI/CD runner defines an untrusted execution environment, not automatic compromise of every repository or secret. Scope the incident by identifying every job that ran during the exposure window.
  • Inventory both workflow-provided credentials and host-resident credentials, then distinguish credentials that were accessible from credentials that audit evidence shows were actually used.
  • Persistent or shared runners can widen the incident to later jobs, other repositories, internal network resources, caches and host credentials even after the original malicious job ends.
  • Rebuilding the runner does not revoke stolen credentials or restore trust in artifacts already built, published or deployed, so credential, repository, artifact and downstream remediation must be tracked separately.

A compromised CI/CD runner can expose much more than the secret that first triggered the incident. The real blast radius depends on which jobs executed while the runner was untrusted, which credentials those jobs or the host could access, which repositories and networks were reachable, and whether artifacts, caches, packages or deployments left the compromised environment.

Direct answer

What should you scope after a CI/CD runner compromise?

Start with the exposure window and enumerate every job that crossed the runner during that period. For each job, map repository access, job tokens, long-lived secrets, environment credentials, cloud identity, package registries, artifacts, caches, signing credentials, network reachability and deployment targets.

Critical distinction

Rebuilding the runner closes only one part of the incident

A clean runner rebuild does not revoke credentials already copied by an attacker, remove malicious artifacts already published, reverse repository changes or undo cloud actions already performed.

Exposure

Credential accessible

Attacker-controlled code could reach a token, secret, host credential or workload identity.

Evidence

Unauthorized use

Audit or service telemetry shows the credential or access path was actually used.

Impact

Downstream compromise

Repository, cloud, registry, artifact, deployment or another connected system was modified or abused.

Runner compromise and malicious workflow execution are not exactly the same incident

A CI/CD workflow is designed to execute repository-controlled automation. If attacker-controlled code reaches a job, that job may access whatever the workflow and runner make available.

A runner compromise is broader. It means the execution environment itself can no longer be trusted.

State What it means Primary investigation concern
Malicious job or action Attacker-controlled code executed during a workflow What that specific job could reach
Runner compromised The execution environment is untrusted Credentials, source, files and network resources reachable from the runner
Persistent runner compromise Unauthorized changes survive after the original job Later jobs and later credentials may also become exposed
CI control-plane compromise Repository, organization or runner-management controls are compromised Potential scope can extend beyond the runner host itself

TPS rule: A compromised runner defines an exposure environment. It does not automatically prove every credential, repository or cloud account connected to the CI platform was compromised.

CI/CD runner compromise evidence ladder from suspect runner to downstream compromise
Runner compromise becomes more serious as evidence progresses from exposed jobs and credentials to unauthorized use, artifact tampering and downstream compromise.

Step 1: Establish the runner exposure window

The investigation becomes manageable only when you establish when the runner stopped being trustworthy.

Build a timeline containing:

  • last known-good runner state
  • first suspicious or malicious execution
  • first confirmed unauthorized execution
  • evidence of persistence, if any
  • every job that executed afterward
  • time the runner was isolated
  • time the runner was removed or rebuilt
  • credential revocation times
  • artifact withdrawal or rebuild times

If the exact compromise time is unknown, use the earliest defensible suspicious point and widen the investigation rather than inventing a precise start time.

THE MALICIOUS JOB ENDING ≠ THE EXPOSURE WINDOW ENDING. On a persistent runner, attacker-controlled changes can survive and capture credentials from later jobs.

Step 2: Identify every job that ran during the exposure window

This is the core blast-radius exercise.

For each job, record:

  • repository
  • workflow name
  • workflow run and job identifier
  • branch, tag or triggering event
  • runner or runner group
  • job permissions
  • referenced secrets
  • environment used
  • cloud role or workload identity
  • package or container registries accessed
  • artifacts created or downloaded
  • caches restored or written
  • deployment targets
  • internal network resources reachable

GitHub’s current security-incident guidance specifically recommends using workflow runs and logs to determine what executed, which credentials a job could access and how suspicious activity correlates with audit events.

Repository exposure is not one single state

A runner normally receives source code because it must build or test it. Repository impact should therefore be classified separately.

Code read

Private source checked out onto the runner may be visible to attacker-controlled processes.

Repository write

A token with write permission may allow commits, tags, branches or other repository changes.

Release / workflow influence

Broader permissions may allow changes that affect future CI executions or software releases.

NO SECRET STOLEN ≠ NO SOURCE CODE EXPOSED. Source code and credentials are different exposure classes.

If one specific GitHub token becomes part of the investigation, use the TPS guide GitHub Token Exposed: How to Check What It Accessed Before and After Revocation.

Job-scoped CI tokens need lifecycle-aware investigation

GitHub creates a GITHUB_TOKEN for workflow jobs. GitHub’s incident-response documentation states that the token is scoped to the job and cannot be reused after the job finishes, subject to its effective maximum lifetime.

That makes the right questions:

  • What repository did the token belong to?
  • What were its effective permissions?
  • Was the job still active when attacker-controlled code executed?
  • Did audit evidence show API or repository actions during the token’s valid lifetime?

JOB TOKEN EXPIRED ≠ OTHER CREDENTIALS SAFE. Personal access tokens, app tokens, API keys and other long-lived credentials can remain valid after the workflow ends.

Long-lived CI/CD secrets are a different exposure class

Review every long-lived credential actually available to jobs or the runner host during the compromise window.

Examples include:

  • personal access tokens
  • GitHub App or integration credentials
  • third-party API keys
  • SSH keys
  • package-registry credentials
  • container-registry credentials
  • database credentials
  • deployment tokens
  • service-account credentials
  • code-signing keys

If attacker-controlled code could read a long-lived secret, treat it as exposed even if audit logs do not yet prove misuse.

ACCESSIBLE ≠ USED. A credential can require revocation because it was exposed even when there is no evidence it was subsequently abused.

Environment secrets may reduce blast radius — if the job never reached the environment

CI/CD environments can create an important boundary.

For example, GitHub environment secrets are scoped to jobs referencing that environment and can also be protected by approval rules.

Therefore a compromised test job does not automatically prove production environment secrets were materialized.

But persistent runner compromise changes that conclusion. If the same compromised runner later receives an approved production job, malware already present on the host may capture those later credentials.

Environment never reached

The production secret may never have been delivered to the suspect job.

Persistent runner later used for production

The later production credentials may become part of the exposure window.

Cloud access: static credentials and OIDC require different responses

CI/CD jobs may access AWS, Azure, Google Cloud or another platform through either stored credentials or federated identity.

Static cloud key

If a long-lived cloud credential was accessible to the compromised environment, revoke or rotate it and investigate its cloud audit history.

OIDC / workload federation

OIDC reduces the need to store long-lived cloud secrets. A workflow exchanges its identity for a short-lived cloud token.

That does not mean a compromised runner has zero cloud exposure. If attacker-controlled code executes while the temporary cloud token is valid, it may be able to use the role assigned to the job.

Check:

  • which cloud role could be assumed
  • whether a token was issued during the exposure window
  • the role’s effective permissions
  • cloud audit events under that role
  • repository, branch, environment or workflow conditions on the trust policy
  • whether federation should be temporarily restricted

OIDC REDUCES LONG-LIVED SECRET RISK ≠ ZERO CLOUD RISK DURING THE JOB.

If a static AWS access key becomes one of the exposed credentials, continue with AWS Access Key Exposed: How to Check Whether It Was Used.

Do not limit the inventory to secrets stored in the CI platform

A self-hosted runner can contain credentials that were never configured as repository or organization secrets.

Check the host for:

  • SSH private keys
  • cloud CLI credential files
  • .npmrc or package-manager credentials
  • Maven or Gradle settings
  • Docker credential stores
  • kubeconfig files
  • service-account files
  • machine certificates
  • signing material
  • mounted secret volumes
  • local deployment configuration
  • credential-helper stores

GitLab’s runner security guidance explicitly warns that sensitive files placed on the runner host can be stolen by malicious jobs.

CI SECRET INVENTORY ≠ COMPLETE RUNNER CREDENTIAL INVENTORY.

What could the runner reach without stealing another secret?

Network placement can make a self-hosted runner materially more powerful than its CI secret configuration suggests.

Investigate access to:

  • corporate LAN services
  • cloud VPC resources
  • Kubernetes APIs
  • internal databases
  • private package repositories
  • artifact stores
  • deployment endpoints
  • cloud metadata services
  • Docker daemon or local privileged sockets
  • internal APIs relying on network trust

GitLab recommends runner network segmentation and restrictions around cloud metadata access because malicious CI code can otherwise reach infrastructure beyond the immediate job.

Ask a separate question: What could this machine access simply because of where it was running?

Persistent and shared runners widen the investigation

Ephemeral and persistent runners should not be treated as equivalent.

Runner model Primary exposure boundary Main concern
Ephemeral runner Usually one job or short-lived execution environment Credentials and outputs from that execution
Persistent self-hosted runner Multiple jobs across time Persistence can expose later jobs and host data
Shared runner Multiple repositories or projects One compromised host may cross repository boundaries
Privileged runner May have host-level capability Container or job compromise can become host compromise

GitHub runner groups can be shared with selected repositories. That tells you which repositories could have used the runner, but not which repositories were actually exposed.

RUNNER GROUP ACCESS ≠ PROVEN REPOSITORY EXPOSURE. Use the allowed-repository list to define what to investigate, then identify the jobs that actually executed during the window.

Caches can become a future-execution path

A compromised runner can create cache risk even if no long-lived secret was stolen.

Investigate:

  • cache keys written during the compromise window
  • dependency caches
  • compiler and build caches
  • tool caches
  • which later trusted jobs restored those caches

GitHub’s guidance is to treat cache content as untrusted and not store secrets in caches.

A poisoned cache can potentially influence later trusted workflows.

CACHE POISONED ≠ SECRET STOLEN. It is an integrity and persistence problem that can survive beyond the original malicious job.

Artifacts produced on the runner may no longer be trustworthy

A runner often builds the software that later becomes a release or deployment.

For every artifact produced during the exposure window, determine:

  • what source commit it used
  • which workflow and job built it
  • whether attacker-controlled code could modify build inputs or outputs
  • where the artifact was uploaded
  • whether it was released or published
  • whether another system deployed or consumed it

Confidentiality exposure

Attacker could read private artifacts, logs or generated output.

Integrity exposure

Attacker could modify the artifact before publication or deployment.

RUNNER CLEANED ≠ ARTIFACT TRUST RESTORED. Suspect builds may need to be quarantined and rebuilt from a trusted environment.

What can artifact attestations prove?

Artifact provenance can help identify which repository, workflow, environment, commit and triggering event produced a build.

That is useful for scoping.

It does not mean an artifact produced by a compromised runner is automatically safe. Provenance can tell you that a suspect execution produced the artifact, which may be a reason to quarantine and rebuild it.

Package registries and signing keys can turn the incident into a supply-chain compromise

Review any runner access to:

  • npm
  • PyPI
  • Maven repositories
  • NuGet feeds
  • container registries
  • GitHub Packages
  • GitLab Package Registry
  • private artifact repositories

Determine whether the credential was read-only or could publish, overwrite or promote packages.

Signing credentials require especially careful treatment. If a runner could access a code-signing, package-signing or container-signing key, an attacker may be able to produce malicious output that appears legitimate.

A CI/CD runner incident can become a software supply-chain incident even when no production server was directly accessed.

Secret masking in logs does not prove the secret was protected

CI platforms can redact known secrets from displayed logs.

That protects the log output. It does not prevent code executing inside the job from reading a secret that has already been supplied to the process.

SECRET MASKED IN LOG ≠ SECRET NOT ACCESSIBLE TO THE JOB.

Logs remain useful for identifying commands, dependencies, uploads, suspicious URLs and execution timing, but they are only one evidence source. GitHub also notes that workflow logs capture standard output, not every file-system modification, network call or background process.

Separate exposure from actual misuse

The investigation should preserve four different states.

ACCESSIBLECredential or resource was reachable
EXPOSEDAttacker-controlled code could obtain or influence it
USEDAudit evidence shows authentication or access
ABUSEDUnauthorized modification, publication or deployment occurred

Do not downgrade an exposed long-lived credential merely because no misuse has yet been observed. But also do not report every potentially reachable resource as confirmed compromised without evidence.

Use this runner blast-radius matrix

Exposure class Primary questions
Repository What code was checked out and what write permissions existed?
Job token What was the token scope, permission and valid lifetime?
Long-lived secrets Which PATs, API keys, SSH keys and service credentials materialized?
Environment secrets Which protected environments did affected jobs actually reach?
Cloud Which static key or OIDC role was available and what actions occurred?
Runner host Which local credential files, machine identities or mounted secrets existed?
Network Which internal services could the runner reach because of its placement?
Cache Which caches were read or written and were they later restored?
Artifacts Which builds were created, published, released or deployed?
Registry Could the runner read private packages or publish new versions?
Signing Could the runner use code, package or container signing material?
Other repositories Which repositories actually used the same persistent runner during the exposure window?

Contain the runner before trying to restore trust

For an active incident, the first objective is to stop additional jobs and access paths from crossing the untrusted environment.

Depending on your platform and incident scope:

  • cancel suspicious or in-progress workflow runs
  • stop new jobs from reaching the runner
  • isolate the runner from the network
  • remove or disable the affected self-hosted runner
  • preserve runner disk or VM evidence where practical
  • preserve workflow logs and CI metadata
  • preserve repository and organization audit logs
  • preserve cloud and registry audit events

GitHub’s current incident-response guidance specifically includes cancelling malicious workflow runs, disabling Actions where necessary and removing suspect self-hosted runners as possible containment measures.

Then rotate or revoke credentials according to actual exposure

Prioritize credentials that attacker-controlled code could access.

Possible remediation includes:

  • revoke exposed personal access tokens
  • replace API keys
  • rotate SSH and deployment credentials
  • rotate package-publishing credentials
  • replace signing keys when exposure warrants it
  • review cloud role sessions and static credentials
  • tighten OIDC trust conditions
  • remove and recreate runner authentication where runner identity itself may be compromised

GitHub’s August 18, 2026 credential-management update also added finer-grained token-type and user-specific revocation capabilities for incident response in supported environments.

Rebuild persistent runners from a trusted image

Do not assume that deleting one malicious file returns a long-lived runner to a trustworthy state.

Persistence can exist in:

  • operating-system files
  • services
  • shell startup files
  • runner configuration
  • build tooling
  • container configuration
  • root certificates
  • credential stores
  • scheduled jobs

A safer recovery pattern is to replace or rebuild the runner from a trusted image, then re-register it with fresh runner credentials where applicable.

Restore artifact and repository trust separately

Runner recovery is only one track.

1

CREDENTIAL TRACK

Revoke or rotate materialized long-lived secrets and investigate their use.

2

ARTIFACT TRACK

Quarantine suspect builds and rebuild from a trusted environment.

3

CODE / CLOUD TRACK

Review repository modifications, deployments, cloud activity and downstream systems.

RUNNER REBUILT ≠ CREDENTIALS SAFE ≠ ARTIFACTS TRUSTED.

Recommended eight-state evidence ladder

RUNNER SUSPECTEDUnusual behavior detected
RUNNER COMPROMISEDUnauthorized execution established
JOBS EXPOSEDAffected jobs identified
CREDENTIALS ACCESSIBLESecrets and identities mapped
EXTERNAL ACCESS POSSIBLERepository, cloud and network permissions mapped
UNAUTHORIZED USE OBSERVEDAudit evidence found
CODE / ARTIFACT INTEGRITY AFFECTEDChanges or poisoned outputs established
DOWNSTREAM COMPROMISEMalicious output or access reached another system

Evidence boundary

A runner compromise proves that an execution environment became untrusted. It does not by itself prove every secret, repository, artifact, cloud account or downstream service was compromised. The blast radius should be reconstructed from the runner exposure window, job history, credential availability, effective permissions, host state, network reachability and audit evidence.

CI/CD runner compromise: frequently asked questions

If the runner was compromised, should I rotate every secret in the organization?

Not automatically. First identify which jobs and persistent host resources crossed the compromise window. Long-lived credentials actually reachable by attacker-controlled code should be treated as exposed. Unrelated secrets that never reached the runner should not be reported as compromised without evidence.

Do I need to rotate GITHUB_TOKEN?

GitHub generates the token for workflow jobs and it expires with the job or its effective maximum lifetime. Investigate what permissions it had and whether it was abused while valid. Long-lived credentials referenced by the workflow require separate revocation decisions.

Are production secrets safe if only a test job was compromised?

Potentially, if the production environment was never entered and the runner was ephemeral. On a persistent compromised runner, later production jobs may still expose their credentials to existing attacker persistence.

Does OIDC prevent cloud compromise?

It reduces long-lived cloud-secret exposure, but a compromised job may still use a short-lived cloud token while it is valid. Review the assumed role, trust conditions and cloud audit logs.

If I rebuild the runner, can I trust artifacts already produced?

No. Artifacts created during the exposure window require their own integrity review and may need to be quarantined and rebuilt from a trusted environment.

Can a compromised runner affect another repository?

Yes, especially when a persistent or shared self-hosted runner services multiple repositories. Identify which repositories were allowed to use it, then determine which actually executed jobs during the exposure window.

If no secrets appeared in the workflow logs, are they safe?

No. Secret masking protects displayed log output. It does not prove that code running inside the job could not read the secret before masking occurred.

Bottom line

A compromised CI/CD runner is not simply a leaked-secret incident. It is an execution-environment incident that can cross credentials, source code, repositories, cloud identities, internal networks, caches, artifacts, package registries and deployment systems.

The investigation should therefore begin with the runner’s exposure window and every job that crossed it.

Best evidence chain: runner compromise → affected jobs → credentials and host access → repository/cloud/network permissions → audit evidence → artifact and code integrity → downstream systems.

Last verified: August 22, 2026. Current GitHub and GitLab runner-security, incident-response, credential, OIDC, cache and artifact guidance was reviewed.