EXERCISE 2 — CI/CD Pipeline Integrity Controls (5 defences + why code review is critical) ======================================================================================= THE THREAT MODEL: An attacker gains access to the CI/CD pipeline (via credential theft, an exploited worker, a malicious dependency, etc.) and injects malicious code into the build. If the pipeline has no integrity controls, the attacker's code is built, signed with your credentials, and deployed to production — users run the malicious binary. OWASP reports this as a high-risk attack surface. --- 5 CI/CD INTEGRITY DEFENCES (what each prevents + how absence enables attacks): 1. LEAST PRIVILEGE (CI/CD Workers) What it prevents: - If a CI worker is compromised (malicious package, code injection), the attacker's code runs with the worker's permissions. Least privilege limits the damage: a worker can build code but CAN'T ssh to prod, CAN'T access secrets it doesn't need, CAN'T push to main. How absence enables attacks: - Overprivileged worker: attacker gains access, runs "ssh prod-server" and executes arbitrary commands as root. Or: attacker reads PROD_DB_PASSWORD from the worker's environment and uses it to breach production. - Fix: workers run in containers with minimal permissions; they can only do what the build needs (compile, test, push to staging registry). Prod secrets, ssh keys, and deploy credentials are NOT in the worker env; they live in a separate secrets manager that the worker can't access directly. 2. AUDIT LOGGING What it prevents: - Every CI/CD action (build start, secret access, deploy, code push) is logged. If an attacker makes changes, the logs show WHAT, WHO, WHEN. Audit logs enable detection after the fact (forensics) and in real-time (alerting on unusual patterns). How absence enables attacks: - No logging: attacker gains access, runs a malicious build, deploys it, and covers their tracks. You have no idea when the compromise happened or what changed. Discovery happens only when users report problems. - Fix: log ALL actions with tamper-proofing (logs sent to immutable storage, e.g. a dedicated audit system). Alert on anomalies (e.g. someone pushing to main at 3 AM, or a deploy outside business hours). 3. CODE REVIEW BEFORE MERGE (MOST CRITICAL — see below) What it prevents: - Every change to production code requires a human to read it and approve. A malicious commit (either by a compromised account or an attacker who gained repo access) must pass human scrutiny. A human can spot obviously malicious code (calls to system(), shell commands, suspicious diffs). How absence enables attacks: - Auto-merge without review: attacker pushes malicious code to a branch, a bot auto-merges it to main (via CI passing tests or reaching a PR age threshold), and it's deployed before anyone notices. Or: attacker gains access to a maintainer account and pushes directly to main. - Fix: require human approval from a trusted maintainer before ANY merge to main. No bots can bypass this. Multi-reviewer approvals for sensitive changes. 4. SIGNED COMMITS What it prevents: - Code commits are GPG-signed (signed with a developer's private key). The CI system verifies the signature before merging. An attacker who gains repo access but doesn't have the signing key CAN'T commit unsigned code. CI rejects unsigned commits to main. How absence enables attacks: - Unsigned commits: attacker gains access to a repo (via leaked creds, phishing, or a compromised account) and pushes malicious code directly to main. No signature verification, so the code is built and deployed. - Fix: all commits to main must be signed; CI enforces it. Also: developers need secure key storage (hardware keys, gpg-agent with a passphrase). 5. ARTIFACT SIGNING + VERIFICATION What it prevents: - The build produces a binary/Docker image/package. That artifact is signed with a private key (separate from signing keys used for commits). The deploy step VERIFIES the signature before running the artifact. An attacker who modifies the artifact AFTER the build (or intercepts it in transit) can't create a valid signature — the deploy fails. How absence enables attacks: - Unsigned artifacts: attacker intercepts the artifact in transit (MITM, compromised registry), replaces it with a trojan, and the deploy runs it unsigned. Or: attacker modifies an artifact in the registry, and the deploy doesn't verify. - Fix: sign artifacts with a trusted key; verify signatures at deploy time. Use container-image signing (Sigstore, Docker Content Trust), code-signing certificates for binaries, or package signatures (npm, apt). --- WHY CODE REVIEW IS THE MOST CRITICAL: Code review sits at the JUNCTION of development and deployment. It's the last human-controlled step. The other four defences are TECHNICAL: - Least privilege: limits what a compromised worker can do. - Audit logging: lets you detect compromise (after). - Signed commits: prevents unsigned code. - Signed artifacts: prevents tampered binaries. But if an attacker: - Gains a trusted developer's account (phishing, credential stuffing), they can sign commits, and a signature doesn't catch the malicious code. - Compromise is subtle (a legitimate-looking function that exfiltrates data), and the code is signed/verified. Code REVIEW catches these because a human reads the code. A human spots: - Unexpected system calls (shell, file access, network requests). - Suspicious diffs (extra dependencies, changes to deploy config). - Logic that doesn't match the PR description. Example: "Add new user API endpoint" PR. The diff shows the new endpoint function, plus a line that writes the request body to a file in /tmp, plus a new dependency on a sketchy package. A human reviewer says "why are we doing that?" and blocks the merge. Signed commits and artifacts don't catch it. The attacker's easiest paths into your production are: 1. Compromise a developer account + push code to main (code review blocks). 2. Exploit the build process (signed commits/artifacts block after-build tamper). 3. Gain overprivileged access to the CI worker (least-privilege blocks). Code review blocks path 1, which is why it's the most critical. The others are defence in depth. --- SUMMARY TABLE: Defence | Prevents What | Why Absence Fails ---------------------|---------------------------------------|----------------------------- Least privilege | Attacker uses worker to breach prod | Overprivileged worker = full system access Audit logging | Undetected compromise | No logs = no forensics, no real-time alerts Code review | Malicious code merged without notice| Auto-merge or direct-to-main bypass Signed commits | Unsigned attacker code | Unsigned commits accepted Signed artifacts | Tampered binaries deployed | Artifacts verified after push CODE REVIEW IS MOST CRITICAL: it's the last human gate before production. The others are technical defences; code review catches subtle/legitimate-looking attacks.