The CircleCI security incident in January 2023 — where an engineer's laptop compromise led to the exfiltration of customer secrets — was a wake-up call. It demonstrated that even well-run CI/CD platforms can be breached, and that your security posture must assume the platform itself could be compromised.
This guide covers how to configure CircleCI securely, limit blast radius when something goes wrong, and detect anomalies before they become incidents.
Lessons from the January 2023 Breach
CircleCI disclosed that an attacker gained access to production systems through a compromised SSO session on an employee's machine. The attacker accessed customer environment variables and secrets stored in CircleCI's infrastructure.
The key takeaway: secrets stored in any third-party CI/CD platform are only as secure as that platform's internal security. You need to minimize what you store and have a rotation plan.
Context Security
CircleCI contexts group environment variables and restrict which projects and branches can access them. This is your primary isolation mechanism.
workflows:
deploy:
jobs:
- deploy-production:
context:
- production-aws
filters:
branches:
only: main
Best practices for contexts:
- Create granular contexts: One context per environment per service. Do not dump all credentials into a single "deploy" context.
- Restrict contexts to specific projects: Use security groups to limit which CircleCI projects can use a context.
- Restrict to specific branches: Production contexts should only be accessible from the
mainbranch. - Audit context usage: CircleCI's audit logs show which jobs accessed which contexts. Monitor for unexpected access.
Use OIDC Instead of Static Credentials
After the January breach, CircleCI accelerated support for OIDC tokens. Use them for every cloud provider that supports it.
jobs:
deploy:
docker:
- image: cimg/aws:2023.01
steps:
- run:
name: Assume AWS Role via OIDC
command: |
aws sts assume-role-with-web-identity \
--role-arn arn:aws:iam::123456789:role/circleci-deploy \
--web-identity-token $CIRCLE_OIDC_TOKEN \
--role-session-name circleci-${CIRCLE_BUILD_NUM}
OIDC tokens are short-lived and verifiable. If CircleCI is breached again, there are no static credentials to steal — only token issuance infrastructure that you can revoke by removing the trust relationship on your cloud provider's side.
Vet Orbs Before Use
CircleCI orbs are reusable configuration packages, analogous to GitHub Actions. The same supply chain risks apply.
- Prefer certified orbs from CircleCI and verified partners.
- Read the source of community orbs before using them. Orb source is always public.
- Pin orbs to specific versions, not
volatileor@latest. - Check the orb's update history and maintainer activity.
orbs:
# Pinned to specific version
aws-cli: circleci/aws-cli@3.1.4
# Bad — mutable reference
# aws-cli: circleci/aws-cli@volatile
If an orb does something simple — like installing a CLI tool — consider writing the three lines of shell script yourself instead of depending on external code.
Secure Self-Hosted Runners
CircleCI's self-hosted runners bring builds into your infrastructure. This gives you more control but also more responsibility.
- Run each job in an ephemeral container or VM. CircleCI's machine runner supports this with the
--single-taskflag. - Do not install runners on machines that also serve other purposes. Dedicated runner infrastructure only.
- Restrict which projects can target your self-hosted runners using runner resource classes.
- Monitor runner machines with your standard endpoint detection and response tooling.
- Rotate runner tokens regularly.
Pipeline Configuration Security
Your .circleci/config.yml is infrastructure code. Treat it accordingly:
- Store it in a protected branch with required code reviews.
- Use CircleCI's config policies (available on Scale plan) to enforce organizational standards.
- Prohibit inline shell scripts longer than a few lines — extract them into scripts stored in the repository where they can be reviewed and tested.
# Prefer this
steps:
- run: ./scripts/deploy.sh
# Over this
steps:
- run:
command: |
# 50 lines of shell that nobody reviews
...
Restrict SSH Access
CircleCI allows SSH debugging — you can SSH into a running job to troubleshoot failures. This is useful but dangerous in production contexts.
- Disable SSH debugging for production workflows.
- If you must allow it, restrict it to specific users and audit all SSH sessions.
- Set a short timeout so abandoned SSH sessions do not persist.
Monitor Build Artifacts and Caches
CircleCI caches and artifacts persist between builds. An attacker who compromises one build can poison the cache to affect future builds.
- Use cache keys that include a hash of relevant files (lockfiles, Dockerfiles).
- Periodically clear caches to prevent long-lived poisoning.
- Sign build artifacts and verify signatures before deployment.
- restore_cache:
keys:
- deps-v2-{{ checksum "package-lock.json" }}
# Fallback, but be aware this could use a poisoned cache
- deps-v2-
Audit Logging and Alerting
CircleCI provides audit logs for organization-level events. Export them to your SIEM and create alerts for:
- New contexts created.
- Context variables modified.
- New SSH keys added.
- Runner tokens created or rotated.
- Config policy changes.
- Unusual build patterns (builds at odd hours, builds from unexpected branches).
Secret Hygiene
After the January 2023 incident, CircleCI recommended rotating all secrets. This should not be a one-time event:
- Rotate all CI/CD secrets quarterly at minimum.
- Use short-lived tokens wherever possible (OIDC, temporary credentials).
- Implement automated secret rotation for long-lived credentials.
- Maintain an inventory of what secrets exist in CircleCI and who added them.
How Safeguard.sh Helps
Safeguard.sh monitors your CircleCI configuration alongside your broader CI/CD infrastructure. It inventories every context, secret reference, and orb dependency across all your CircleCI projects. When CircleCI (or any other CI/CD platform) discloses a security incident, Safeguard.sh provides an immediate impact assessment — showing exactly which secrets, projects, and deployment pipelines are affected. It enforces policy-as-code rules that catch insecure configurations before they reach production, and maintains the audit trail that compliance frameworks require.