Deliberately vulnerable CI/CD environment. Hack CI/CD pipelines, catch the flags. 🚩
Created by Cider Security.
The CI/CD Goat project allows engineers and security practitioners to learn and practice CI/CD security through a set of 10 challenges, enacted against a real, full blown CI/CD environment. The scenarios are of varying difficulty levels, with each scenario focusing on one primary attack vector.
The challenges cover the Top 10 CI/CD Security Risks, including Insufficient Flow Control Mechanisms, PPE (Poisoned Pipeline Execution), Dependency Chain Abuse, PBAC (Pipeline-Based Access Controls), and more.
The different challenges are inspired by Alice in Wonderland, each one is themed as a different character.
The project’s environment is based on Docker images and can be run locally. These images are:
- Gitea (minimal git server)
- Jenkins
- Jenkins agent
- LocalStack (cloud service emulator that runs in a single container)
- Lighttpd
- CTFd (Capture The Flag framework).
The images are configured to interconnect in a way that creates fully functional pipelines.
There's no need to clone the repository.
curl -o cicd-goat/docker-compose.yaml --create-dirs https://raw.githubusercontent.com/cider-security-research/cicd-goat/main/docker-compose.yaml
cd cicd-goat && docker-compose up -d
curl -o cicd-goat/docker-compose.yaml --create-dirs https://raw.githubusercontent.com/cider-security-research/cicd-goat/main/docker-compose.yaml
cd cicd-goat && docker-compose up -d jenkins_server
- Wait for Jenkins to fully boot.
docker-compose up -d
mkdir cicd-goat; cd cicd-goat
curl -o docker-compose.yaml https://raw.githubusercontent.com/cider-security-research/cicd-goat/main/docker-compose.yaml
get-content docker-compose.yaml | %{$_ -replace "bridge","nat"}
docker-compose up -d
- Spoiler alert! Avoid browsing the repository files as they contain spoilers.
- To configure your git client for accessing private repositories we suggest cloning using the http url.
- In each challenge, find the flag - in the format of flag# (e.g flag2), or another format if mentioned specifically.
- If needed, use the hints on CTFd.
- There is no need to exploit CVEs.
- No need to hijack admin accounts of Gitea or Jenkins (named "admin" or "red-queen").
-
Login to CTFd at http://localhost:8000 to view the challenges:
- Username:
alice
- Password:
alice
- Username:
-
Hack:
- Jenkins http://localhost:8080
- Username:
alice
- Password:
alice
- Username:
- Gitea http://localhost:3000
- Username:
thealice
- Password:
thealice
- Username:
- Jenkins http://localhost:8080
-
Insert the flags on CTFd and find out if you got it right.
- If Gitea shows a blank page, refresh the page.
- When forking a repository, don't change the name of the forked repository.
Warning: Spoilers! 🙈
See Solutions.
-
Clone the repository.
-
Rename .git folders to make them usable:
python3 rename.py git
-
Install testing dependencies:
pip3 install pipenv pipenv install --deploy
-
Run the development environment to experiment with new changes:
rm -rf tmp tmp-ctfd/ cp -R ctfd/data/ tmp-ctfd/ docker-compose -f docker-compose-dev.yaml up -d
-
Make the desired changes:
- All services except CTFd are completely configured as code so desired changes should be made to the files in the appropriate folders.
- To make changes in CTFd, use the admin credentials.
-
Shutdown the environment, move changes made in CTFd and rebuild it:
docker-compose -f docker-compose-dev.yaml down ./apply.sh # save CTFd changes docker-compose -f docker-compose-dev.yaml up -d --build
-
Run tests:
pytest tests/
-
Rename .git folders to allow push:
python3 rename.py notgit
-
Commit and push!
Follow the checklist below to add a challenge:
- CTFd:
- Write challenge description.
- Choose category according to difficulty level.
- Make sure the challenge is visible and has value according to difficulty.
- Write hints in order of usage.
- Add a flag. Make sure to select if it's case-insensitive.
- Gitea:
- Configure a new repository in gitea.yaml.
- Create the repository under gitea/repositories. Use an open-source repository that use the MIT license as a template for the challenge repository.
- Jenkins:
- Configure Jenkins and add new jobdsl files in the casc.yaml file.
- Make sure jobs don't run periodically. Jobs should be triggered by events / polling.
- Validate that the new challenge doesn't interfere with other challenges.
- Make sure the flag is not accessible when solving other challenges.
- Write tests.
- Write the solution.
- Update README.md if needed.