Building a DevSecOps pipelineModule 1: Foundations and your lab repository

Course orientation: how this course works, and why it matters now

How the modules, labs, checkpoints and capstone fit together, the repository you will build, and the real 2024–2026 supply-chain attacks that each module is designed to stop.

This lesson
QuestionsPass 7/10
Course26 items

In this lesson you will

  • Describe how each module moves from lessons to a lab to a checkpoint, and how the capstone ties the course together
  • Name the tools you will use and what the devsecops-lab repository will contain by the end
  • Connect recent real supply-chain attacks to the pipeline control that would have stopped or contained them

How this course is built

The course has six modules. Each one follows the same rhythm:

  1. Lessons. Short, focused pages, each on one topic, with a Try it block you can run on your own machine.
  2. A lab. Step-by-step work in your own repository. Each lab adds jobs to a single pipeline and ends with a “Check your work” list. Module 6 has a capstone project in place of a lab.
  3. A checkpoint. A quiz across the whole module, with questions you have not seen in the lessons.

At the end, a capstone brings every job together and asks you to prove the pipeline works by trying to break it. A final assessment then tests the whole course.

Every page ends with its own questions. Answer them all and check them: get at least 7 in 10 right and the page is passed, and the next one opens. You can try as often as you like, and after three tries the answers and explanations are shown.

Module 1 is open to everyone. To go further, sign in with your email address: there is no password, just a one-time link. Your progress is then saved to your account, so it follows you to any device, and the outline beside each lesson shows what you have passed and what is still locked.

What you will build

One public GitHub repository, devsecops-lab, containing a small Python web service and a pipeline that grows module by module:

Module Job you add What it stops
1 smoke A broken build reaching review (the baseline the others build on)
2 secrets Credentials committed to the repository
3 sast, deps Injection bugs in your code and known-vulnerable libraries
4 iac Open security groups, public buckets, unencrypted storage
5 image Vulnerable base images, unknown contents, unsigned artifacts
6 test, dast, evidence Missing security headers, untested changes, and no proof for an auditor

The tools are free and open source: Gitleaks, Semgrep, pip-audit, Trivy, Checkov, Conftest, Syft, Cosign and OWASP ZAP, run on GitHub Actions. The ideas carry over to GitLab CI, Bitbucket Pipelines, Jenkins and Azure DevOps.

The threat landscape now

The attacks that matter most to a delivery pipeline in the last few years did not exploit the application. They came in through the build: through dependencies, CI configuration and the tokens pipelines hold. Five incidents show the pattern, and each module in this course answers one of them.

xz-utils: a trusted dependency, backdoored (March 2024)

Malicious code was found in versions 5.6.0 and 5.6.1 of XZ Utils, a compression library shipped in many Linux distributions. It was tracked as CVE-2024-3094 with the maximum severity score. The backdoor was planted by a contributor who had spent a long time gaining maintainer trust, and it lived in release tarballs rather than in the visible source tree. CISA advised downgrading to an uncompromised version.

Lesson: popularity is not proof of safety. You need to know exactly which versions you run (module 3) and what is inside every artifact you ship (module 5).

Ultralytics: a pull request that became a release (December 2024)

An attacker opened a pull request against the Ultralytics repository with a shell payload in the branch name. A workflow triggered by pull_request_target, which runs with the base repository’s secrets, passed that name to a shell. The attacker used the foothold to poison the build cache, and the project’s own publishing workflow then released versions 8.3.41 and 8.3.42 to PyPI with a cryptominer inside.

Lesson: pipeline configuration is code with privileges. Threat modelling the pipeline itself covers pull_request_target and injection through untrusted inputs.

tj-actions/changed-files: a third-party action, repointed (March 2025)

Attackers modified the version tags of the popular tj-actions/changed-files GitHub Action so that every tag from v1 to v45.0.7 pointed at a malicious commit. Workflows that referenced the action by tag ran code that dumped secrets into build logs. CISA tracked it as CVE-2025-30066 and advised rotating every secret the affected workflows could reach.

Lesson: a tag is not a version you reviewed. The module 3 lab pins every action to a full commit SHA, and Securing the repository covers the organisation policy that can require it.

s1ngularity: a pull request title that stole a publishing token (August 2025)

The Nx build system’s maintainers reported that a workflow using pull_request_target echoed pull request titles into a shell. An attacker injected code through a title, used the workflow’s read-and-write token to trigger the publishing workflow, and stole the npm token. Malicious Nx versions then harvested developers’ credentials and uploaded them to public repositories.

Lesson: least-privilege tokens and short-lived publishing credentials (module 2), and short-lived deploy credentials (module 6), shrink what one bug can reach.

Shai-Hulud: a self-replicating npm worm (September 2025)

A worm compromised more than 500 npm packages. Once installed, it searched the machine for GitHub tokens and cloud keys, sent them to the attacker, and used stolen npm credentials to publish infected versions of the victim’s other packages. CISA recommended pinning dependencies to known-good versions, rotating developer credentials and enforcing phishing-resistant MFA. In response, npm moved to short-lived sessions, retired classic tokens in December 2025, and pointed CI publishing at trusted publishing with OIDC.

Lesson: long-lived tokens are the fuel these attacks run on. Module 2 teaches you to keep them out of repositories and, better, to stop needing them at all.

Try it: count your own long-lived tokens

Before you start, take stock of your own exposure. On a machine you use for development, run:

# Tokens and keys that tools commonly store in your home directory
ls -la ~/.npmrc ~/.pypirc ~/.aws/credentials ~/.docker/config.json \
  ~/.config/gh/hosts.yml 2>/dev/null

# Environment variables that look like credentials (names only, not values)
env | cut -d= -f1 | grep -Ei 'token|secret|key|password' || true

Every file or variable you find is something the Shai-Hulud worm would have gone looking for. You do not need to change anything yet; by module 2 you will know which of them can be replaced with short-lived credentials.

How to get the most out of the course

  • Do the labs. The lessons explain; the labs are where the controls become real. Each lab assumes the previous one is finished.
  • Break things on purpose. Every lab has a step where you add a vulnerability, a fake key or a misconfiguration and watch the pipeline catch it. A check you have never seen fail is a check you cannot trust.
  • Answer before you reveal. Choose an answer to each practice question before opening it. The explanations say why the other answers are wrong, which is where most of the learning is.

Further reading

Key takeaways

  • Every module follows the same rhythm: short lessons, one hands-on lab, then a checkpoint quiz.
  • You build one repository, devsecops-lab, and each lab adds a job to the same pipeline.
  • The recent attacks in this lesson came through pipelines, tokens and dependencies, not through the application's own code.
  • Each module closes one of the doors those attacks used: secrets, dependencies, infrastructure, artifacts or deployment.
  • Module 1 is open to everyone; sign in to save your progress and unlock each later lesson by passing the one before it.

Lesson questions

Answer all 10, then check them. You need 7 right to pass this lesson and unlock the next one. Try as often as you like; after three tries the answers and explanations are shown. These are our own questions, written for this course.

  1. In March 2025, attackers moved the version tags of the tj-actions/changed-files GitHub Action to point at malicious code. Which control would have stopped workflows from picking up the change?
  2. Once installed on a developer's machine, what did the September 2025 Shai-Hulud worm go looking for?
  3. The xz-utils backdoor (CVE-2024-3094) was hidden in release tarballs of a widely used compression library. What does this incident teach about dependencies?
  4. What does a module checkpoint in this course do?
  5. You complete half the course on a work laptop, signed in, and continue on a home computer. What do you need to do to pick up where you left off?
  6. In the Ultralytics attack (December 2024), how did the attacker first get code to run in the project's workflow?
  7. Which module of this course adds the job that catches open security groups, public buckets and unencrypted storage?
  8. What common thread links the xz-utils, tj-actions, s1ngularity and Shai-Hulud incidents described in this lesson?
  9. Every lab has a step where you add a fake key or a vulnerability on purpose. Why?
  10. After the Shai-Hulud worm, which change did npm make to reduce the value of stolen publishing credentials?

Courses are taught against the frameworks they name. That is alignment, not certification: no course is certified, approved or endorsed by NIST, the DoD, DISA, FedRAMP, the CMMC program or any other agency or standards body, and completing one does not make a system compliant.