Skip to content
Severity: criticalConfidence: high

Build Pipeline Compromise: When the Artifact Is the Payload

An intrusion that never touched production directly. The attacker modified a build agent, and the organisation shipped the backdoor itself through its own signed release channel.

Published
Updated
Read time
4 min

Executive summary

Executive summary

  • A self-hosted build agent was reachable from a developer VLAN with no egress filtering and a shared local administrator password.
  • The attacker injected a post-compile step that appended loader code to the release artifact before signing, so every downstream integrity check passed.
  • Dwell time was 41 days. Detection came from a customer reporting anomalous outbound traffic, not from internal monitoring.
  • Signing infrastructure was never compromised, which is precisely why the attack worked.

Quick facts

Quick facts

Initial access
Reused local admin credential
Dwell time
41 days
Detection source
Downstream customer report
Artifacts affected
3 signed releases
Signing keys stolen
No
Containment
6 days

What made this different#

Most intrusions end where the attacker's access ends. This one ended where the organisation's distribution reach ended — which was considerably further.

The attacker did not steal a signing key, forge a certificate, or interfere with the release approval workflow. They modified the input to a process that was working correctly, and let that process do the rest. Every control downstream of the build agent reported success, because from the perspective of those controls nothing had gone wrong.

Entry and establishment#

The build agent was self-hosted on a physical machine, provisioned three years earlier and excluded from the endpoint agent rollout on the grounds that security tooling had once caused build flakiness. That exclusion was recorded, approved, and never revisited.

Two conditions turned a single credential into full pipeline control:

  • The agent shared a local administrator password with roughly forty developer workstations, none of which enforced unique local credentials.
  • The agent had unrestricted outbound access on 443, justified by dependency fetching from package registries.

Credential recovery from a single developer workstation was therefore sufficient. No exploit was involved at any stage of the intrusion.

The injection#

The pipeline stored part of its definition on the agent's filesystem rather than in version control — a legacy arrangement retained so that a small number of build parameters could be adjusted without a pull request. The attacker edited that local fragment to add a post-compile step.

# Simplified reconstruction of the injected step
- name: optimise-artifact
  run: ./tools/opt.sh --in $ARTIFACT --out $ARTIFACT
  condition: succeeded()

The referenced script performed a genuine, verifiable size optimisation. It also appended a loader stub to the binary's overlay before writing the output. Build logs showed a step that looked plausible, ran quickly, and always succeeded.

Why review did not catch it#

Three properties kept the change invisible:

  1. The modified definition lived outside the repository, so it never appeared in a diff or a pull request.
  2. Build duration increased by under four seconds, well inside normal variance.
  3. The output artifact's hash changed on every build anyway, because the build was not reproducible.

The third point is the important one. Without reproducible builds, there is no baseline hash to compare against, and no way to assert that identical inputs produced identical outputs.

Detection and the telemetry that was missing#

Signal availableCollectedWould have detected
Build agent process creationNoInjected script execution
Local file changes to pipeline configNoThe modification itself
Outbound connections from agentPartialC2 check-in
Artifact hash across rebuildsNoNon-deterministic tampering
Scheduled task creationNoPersistence mechanism

The organisation had mature detection coverage across servers and workstations. The build estate sat in a gap between the platform team, who owned the hardware, and the development team, who owned the workload — and neither had onboarded it.

What would have changed the outcome#

  • Ephemeral build runners. Destroy and rebuild the agent per job. Persistence becomes impossible rather than merely detectable.
  • Pipeline definitions in version control only. No local overrides, no exceptions. Every change becomes reviewable by construction.
  • Reproducible builds with independent verification. A second builder producing a matching hash converts tampering into an immediate, unambiguous alert.
  • Unique local administrator credentials. Removes the lateral path that started the intrusion.
  • Egress allow-listing on build infrastructure. Package registries are a short, knowable list.

Assessment#

Confidence in this reconstruction is high: the pipeline configuration change, the scheduled task and the artifact overlay were all recovered intact during forensics. Attribution is not assessed, and the tooling recovered was generic.

The organisational lesson is narrower than "sign your artifacts" and harder to act on. Build infrastructure is production infrastructure. It was treated as developer tooling for three years, and the exception that excluded it from monitoring outlived everyone who understood why it was granted.

Timeline

Sequence of events

  1. T+001

    Credential reuse on build agent

    An administrator password recovered from a workstation credential store authenticated successfully against the build agent over SMB.

  2. T+202

    Persistence via scheduled task

    A task masquerading as a telemetry uploader re-established the implant after each agent reboot.

  3. T+903

    Pipeline definition modified

    A post-compile hook was added to the pipeline configuration stored on the agent rather than in version control.

  4. T+1404

    First trojanised release signed and published

    The signing service received a modified artifact and signed it exactly as designed.

  5. T+4105

    External notification

    A customer network team reported beaconing from a host running the vendor-supplied agent.

  6. T+4706

    Containment complete

    Pipeline rebuilt from scratch on ephemeral runners; affected releases revoked and reissued.

Tags

  • supply chain
  • ci/cd
  • code signing
  • persistence

Sources

References

Related records