Securing Secrets in Travis CI with Encrypted Environment Variables
Learn how Travis CI encrypted environment variables protect API keys and tokens in .travis.yml, how to add them with the CLI, and what limits apply to fork builds.
15 Jul 2026, 20:37 UTC

Putting an API key, password, or deployment token directly into .travis.yml means anyone with read access to the repository sees it in plaintext. Travis CI's encrypted environment variables let you keep the configuration in version control while ensuring only the build service can read the secret. The mechanism relies on a repository-specific RSA key pair: the public key encrypts the value into a secure string, and the private key, held by Travis workers for that repository, decrypts it at job startup.
How the encryption boundary works
When you run the Travis CLI to encrypt a variable, it fetches the repository's public key from Travis and encrypts the value locally. The resulting ciphertext is committed to .travis.yml. Because the private key never leaves Travis infrastructure, the committed string is useless to anyone who does not control the repository's Travis integration. At build time, the worker decrypts the value and exports it into the job's environment, making it available to scripts exactly like a normal variable.
Worked example: adding a global secret
Run the following from the root of your cloned repository. You must be authenticated with the Travis CLI (travis login) and have push access to the repository:
# Encrypt a value and append it to .travis.yml automatically
travis encrypt STRIPE_API_KEY=sk_test_51Mz... --add env.global
The CLI modifies .travis.yml in place. The generated block looks similar to this:
env:
global:
- secure: "RAE9QAAAAABm6X...Z1R2S3T4U5V6..."
Use env.global when every job in the build matrix needs the secret. If only a deployment stage requires it, use the job-level env key instead so the value is not exposed to unrelated jobs:
jobs:
include:
- stage: deploy
env:
- secure: "RAE9QAAAAABm6X...Z1R2S3T4U5V6..."
The same secure mechanism protects other sensitive keys. For example, a deployment provider API key can be stored as:
deploy:
provider: heroku
api_key:
secure: "RAE9QAAAAABm6X...Z1R2S3T4U5V6..."
Checking that the secret arrives
After committing the change, trigger a build. To verify the variable is present without writing its value to the logs, add a temporary diagnostic to your script section:
script:
- if [ -z "$STRIPE_API_KEY" ]; then echo "secret missing"; else echo "secret present"; fi
- echo -n "$STRIPE_API_KEY" | wc -c
If the job reports the expected character count, the encryption and injection worked. Remove these lines immediately afterward; leaving them in place adds noise and risks accidental exposure if someone later replaces the length check with a direct echo.
Limits and common mistakes
-
Fork pull requests do not receive secrets
Travis withholds encrypted variables from builds triggered by pull requests opened from forked repositories. This prevents a malicious contributor from stealing secrets by submitting a pull request. The trade-off is that integration tests depending on those variables will be skipped or fail silently in fork builds. If your test suite requires the secret, guard the relevant job with a conditional that checks the repository owner or the
TRAVIS_PULL_REQUESTvalue. -
Encrypted strings are bound to the repository
A
securevalue can only be decrypted by the Travis workers for the repository that owns the RSA key pair. If you rename, transfer, or regenerate the key for the repository, every existingsecurestring becomes invalid and must be re-encrypted with the new key. -
Decrypted values are visible in logs
The variable is encrypted on disk but decrypted in plaintext inside the build environment. Running
env,printenv, orecho $VARin a script prints the secret to the build log. For public repositories, those logs are world-readable. -
Write access is equivalent to secret access
Anyone who can push to the repository can also trigger a build that uses the encrypted variables. Repository permissions are part of the security boundary; do not treat encryption as a substitute for access control.
Web UI as an alternative
Instead of committing encrypted strings, you can define variables in the Travis web interface under Repository Settings > Environment Variables on travis-ci.com. Values entered there are stored by Travis and injected at runtime without appearing in .travis.yml. This keeps the config file free of ciphertext, but it also means the secret is invisible to contributors reviewing the file, and the same fork pull request restriction applies. Choose the CLI method when you want the configuration to be self-documenting and reviewable; choose the UI method when you want to rotate values without touching version control.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.