Safeguard
Security Guides•

How do I use credentials in a Jenkins pipeline without leaking them?

Reference credentials by ID, bind them with withCredentials or credentials(), use single quotes in shell steps, and treat masking as partial protection.

Safeguard Security Team
3 min read

Store the secret in the Jenkins credentials store, reference it by ID, and bind it to a variable with the credentials() helper or a withCredentials block. Use single quotes in shell steps so the shell, not Groovy, expands the value. Jenkins masking only reduces accidental exposure, so do not rely on it alone.

Why IDs, not values

Jenkins stores credentials encrypted on the controller, and Pipeline projects handle them through credential IDs. Your Jenkinsfile contains the ID, never the secret. Pick a meaningful ID such as a name that says what the credential is for. If you leave it blank, Jenkins generates a GUID, and an ID cannot be changed once set.

Two ways to bind a credential

For secret text and username and password pairs in Declarative Pipeline, use the credentials() helper inside the environment block. For other types, such as SSH keys and certificates, use a withCredentials step, which the Snippet Generator will write for you. Bound variables exist only inside that block, which keeps the secret's lifetime short.

pipeline {
  agent any
  environment {
    API_TOKEN = credentials('my-api-token')
  }
  stages {
    stage('Publish') {
      steps {
        sh 'curl -H "Authorization: Bearer ${API_TOKEN}" https://example.com/upload'
      }
    }
  }
}

The quote rule that matters

Jenkins is blunt here: Groovy string interpolation should never be used with credentials. A double-quoted string is expanded by Groovy before the command runs, so the secret can end up in the process list and in logs. A single-quoted string is passed to the shell, which reads the environment variable.

StyleWho expands the valueVerdict
Double quotes with the variable insideGroovyAvoid for secrets
Single quotes with the variable insideThe shellUse this

Masking is not a vault

Jenkins replaces the secret with four asterisks in console output. The documentation says this only reduces the risk of accidental exposure. A job author who can run arbitrary steps can still print or transform a secret in ways masking does not catch, for example by encoding it first.

Practical habits

  • Scope credentials to the folder or job that needs them, not to everything.
  • Give each pipeline its own credential, so one leak has one blast radius.
  • Rotate a credential after any suspicion it appeared in a log.
  • Limit who has Job/Configure, since that permission can read bound secrets at run time.

Quick check

Does masking make it safe to echo a token?

No. Masking only matches the exact value and reduces accidents. Never print credentials on purpose.

Can I put the token in an environment block as plain text?

Do not. Use credentials() so the value stays in the store and is referenced by ID.

Safeguard's dependency scanning can run in the same pipeline, and policies and gates can fail a build on findings. There is a free scan if you want a quick look first.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.