We want to ensure that unprotected branches cannot affect the builds of protected branches.
However it seems that it is easy for an unprotected branch to poison the cache of protected branches: A malicious user creates a branch with a modified .gitlab-ci.yml
that modifies the cache that is shared with the protected branches…
Couldn’t one use this approach to compromise the build of proteced branches in any Gitlab CI/CD project that uses caches e.g. with “npm install”? Have I missed something or are Gitlab CI/CD caches just insecure by default?
To reproduce
Protected main/master has a .gitlab-ci.yml
file like this:
cache:
key: predictable-value
paths:
- cache
# This mimics e.g. npm install
build-job:
stage: build
script:
- |
if [ -r cache/file ] ; then
echo "cache/file exists"
else
echo "cache/file doesn't exist"
mkdir -p cache
echo "good value" > cache/file
fi
- ls -l cache/file
- cat cache/file
Now a malicious branch introduces:
cache:
key: predictable-value
paths:
- cache
build-job:
stage: build
script:
- echo "hostile value" > cache/file
- ls -l cache/file
- cat cache/file
Boom! Builds made on protected branches are now compromised!
Workaround
Create a protected and masked CACHE_SECRET
variable with a random (unpredictable) value, and use it like:
cache:
key: value-$CACHE_SECRET
... blablabla ...
Now protected branches use a key of value-ohdowoirho3rht
while unprotected values use value-
.
But why isn’t this the default and why doesn’t https://docs.gitlab.com/ee/ci/caching/#good-caching-practices mention this gaping hole with a single word?