Secrets in CI: Store and Scope Them Safely
Handle API keys and credentials in pipelines without leaking them in logs, artifacts, or pull requests.
Netbay Developer Relations
Netbay Engineering
On this page
CI pipelines need credentials: registry logins, deploy tokens, API keys, signing keys. Store them wrong and you leak them into logs, artifacts, and fork pull requests where anyone can read them. This post covers how CI platforms handle secrets, how to scope them tightly, and the habits that keep them out of your build history.
How Secret Stores Work
Modern CI platforms keep secrets in an encrypted store at the workflow, repository, or organization level. A secret is a name-value pair you reference in a job but never print. The platform masks the value in logs — if a masked secret appears in output, it is shown as asterisks. Masking is a convenience, not a guarantee; treat logs as untrusted regardless.
- name: Run deploy with secret
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
run: |
scripts/deploy.shThe pattern is to read from the secret store into an environment variable, then pass that to your script. The value itself never lives in the file or the repository history.
The Two Golden Rules
Two rules prevent the vast majority of CI secret leaks:
- **Never put a real secret value in a file** — not in the repo, not in a committed config, not in an environment example. Secrets referenced by name in config are fine; the *values* belong in the store.
- **Never echo or log a secret** — do not print environment variables, does not cat a file that contains credentials, and do not paste tokens into curl output.
Secrets should also never be required parameters to a run script on the command line unless you accept they may land in process lists and logs.
Scope Secrets to What They Are For
The smaller the blast radius, the safer. Follow these scoping practices:
- Store secrets at the finest granularity that works — repository level unless an org-level secret is genuinely shared.
- Give each environment its own secret. Production deploy tokens must not be usable from a pull request workflow.
- Rotate secrets on a schedule and immediately when anyone with access leaves.
- Use short-lived or scoped tokens where your services support them.
Most breaches of CI secrets are not sophisticated attacks. They are leaked tokens that were too powerful and too long-lived, sitting in public logs.
Environment and Secret Lifecycle
Assign secrets to the right environment when your platform supports environments per deployment target. This is how you keep a production token out of a PR-triggered job. A pull request from a fork runs with a restricted token that typically cannot read secrets, which is intentional: code you have not reviewed should not silently use your production credentials.
deploy:
runs-on: ubuntu-latest
environment: production
needs: [test, build]
steps:
- uses: actions/checkout@v4
- run: |
echo "downloading artifact"
./deploy.sh
env:
PROD_KEY: ${{ secrets.PROD_TOKEN }}Assigning the environment: production means the job can only use secrets explicitly configured for that environment, and you can require manual approval before it runs.
Guard the Pull-Request Path
Every CI platform has a weaker-trust model for pull requests. Configure it explicitly:
- Do not run deploy jobs on PRs at all.
- Do not expose production secrets to PR jobs.
- Treat PR-triggered output as untrusted, review logs for anything masked or surprising.
- Restrict which actors can edit workflows — a workflow that is editable is a backdoor.
Also scan your repositories continuously for committed secrets. A committed token is already compromised; treat the detection as urgent, not cosmetic.
What to Do When a Secret Leaks
If you ever spot a real secret in a log, an artifact, or a commit, do not just delete the line. The value is already exposed and must be treated as compromised. Rotate it immediately, revoke the old value, then remove it from history if it is in a commit. Rotating is the only reliable fix — editing history does not un-leak a value that was already copied.
Takeaway
Store secrets in the platform's encrypted store, reference them by name, inject at runtime, scope them to the environment that needs them, and keep them out of pull-request jobs entirely. Rotate on any doubt. Follow these and your credentials stay out of your build history.
Netbay VPS instances pair naturally with CI secrets — your deploy targets and runners can live on isolated servers you control, provisionable in seconds at netbayhosts.in.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance