
In software systems, secrets are pieces of sensitive information that should only be accessed by authorized people. Tokens, login credentials, SSH keys, and API keys are all examples of secrets. As developers collaborate, they will typically use a repository platform. While many choose GitHub, another popular alternative is Bitbucket.
Bitbucket has first-party support for secrets management, along with more advanced capabilities such as OpenID Connect (OIDC) for keyless authentication and native third-party secret provider integrations. Note that this guide focuses on Bitbucket Cloud. If your team uses Bitbucket Data Center, the self-hosted version, the process for managing secrets may differ depending on your server configuration.
Within Bitbucket, secrets can be managed at three distinct levels:
- Repository-level, for secrets specific to a single repository
- Workspace-level, for secrets shared across multiple repositories
- Environment/Deployment-level, for secrets configured for specific environments like production or staging
While Bitbucket provides a solid foundation for storing and using secrets in CI/CD pipelines, teams with more advanced requirements often benefit from integrating a dedicated secrets management platform like Infisical. These platforms integrate directly with Bitbucket, make it easier to consolidate secrets across services, and include features like secret rotation, versioning, audit logs, and cross-platform accessibility.
For small projects, Bitbucket's native options may be enough. As infrastructure expands and access controls become harder to manage, the differences between built-in tooling and a purpose-built platform become harder to ignore.
Adding Secrets
Before diving into how to manage secrets in Bitbucket, there are some framing matters that are worth noting:
- In order to add secrets, you need admin access for the repository (for repository variables) or admin access for the workspace (for workspace variables).
- If you mark a variable as secured, Bitbucket stores it as an encrypted variable. Once saved, the value is masked and can no longer be viewed in the UI. You can only update it by entering a new value or delete it.
- For repository variables, Pipelines must be enabled (located in Repository Settings → Pipelines → Settings).
- Your organization or workspace may require two-step verification for access (for example, if your admins enforce it). If it is enforced, you will need to enable it before you can work with protected content and Pipelines.
- A
bitbucket-pipelines.ymlfile must exist in the repository.
Adding a Secret to Bitbucket at the Repository Level
First, navigate to the target repository and select Repository settings on the left-hand side.

Next, under Pipelines, navigate to Repository variables.

In the form, enter the variable name and value, then click the padlock icon to mark it as Secured. This ensures the secret is encrypted at rest and masked in the UI and build logs, preventing it from being viewed by other users. Then, click Add.
Adding a Secret with Bitbucket at the Workspace Level
Navigate to your Bitbucket workspace. Click the settings gear icon in the top-right corner near your profile picture, then select Workspace settings.

On the left-hand menu, locate the Pipelines section and click on Workspace variables.

Like before, add the name and value of the secret, and make sure to click the padlock icon to enable Secured. Then, click Add to commit the secret.
Adding a Secret with Bitbucket at the Environment Level
Navigate to your repository and select Repository settings. Then, locate the Pipelines section and click on Deployments.

First, choose the environment (staging, production, etc). Then, once again, add the name and value of the secret, and make sure to enable Secured. Then, click Add to commit the secret.
How to Use Secrets
When working with secrets in Bitbucket Pipelines, keep these principles in mind:
- Do not echo secrets. Bitbucket Pipelines masks secured variable values in build logs, but you should still avoid printing secrets because leaks can happen through logging, artifacts, or mishandled workflow output. Mandiant published research in 2024 showing how secured variables can be exfiltrated to artifacts when improperly handled in pipeline scripts, even though the values appear masked in logs.
- Do not commit secrets to the repository in plain text. Git history is permanent, and even if the commit is fixed later in the tree, the secret is still considered to be exposed.
- Be aware that anyone with write access to a repository can read secured variables. A user with write access can modify the pipeline YAML to send variable values to an external endpoint. Use deployment variables combined with deployment permissions to restrict access to your most sensitive secrets.
Repository and Workspace Variables
Variables in Bitbucket are made available to Pipelines as environment variables. If you define the same variable name in more than one place, Bitbucket resolves the value using this precedence order:
Pipeline run-level variables > Deployment > Repository > Workspace > Default
In your scripts, you can reference a variable using standard environment-variable syntax (for example, $TOPSECRET). Repository variables override workspace variables with the same name, and deployment variables override both.
With this in mind, secrets can easily be injected into pipeline files. For example, to inject TOPSECRET into a bitbucket-pipelines.yml file, you would use:
pipelines:
default:
- step:
name: "Authentication to API"
image: alpine
script:
- echo "Calling API"
- curl -u "user:$TOPSECRET" https://random.api.com/data
Environment/Deployment Variables
To use a deployment variable, specify the target environment using the deployment parameter:
pipelines:
default:
- step:
name: "Authentication to API using Deployment Variable"
image: alpine
deployment: production
script:
- echo "Calling API"
- curl -u "user:$TOPSECRET" https://random.api.com/data
Now, the value of TOPSECRET will be resolved from the production deployment environment. Deployment variables only work within deployment steps, and each deployment environment is independent, so you can use the same variable name with different values for each environment.
Keyless Authentication with OpenID Connect (OIDC)
One of the most effective ways to reduce the number of secrets you need to manage is to eliminate them entirely. Bitbucket Pipelines supports OpenID Connect (OIDC), which allows your pipelines to authenticate with cloud providers like AWS, GCP, and Azure without storing any long-lived credentials in Bitbucket.
With OIDC, Bitbucket Pipelines generates a short-lived identity token for each pipeline step. Your cloud provider verifies this token and issues temporary credentials with scoped permissions. This approach eliminates the need to manually rotate access keys and reduces the blast radius if a pipeline configuration is compromised.
How It Works
- You register Bitbucket Pipelines as an OpenID Connect identity provider in your cloud account (for example, in AWS IAM).
- You create a role in your cloud provider that trusts the Bitbucket OIDC provider and has the permissions your pipeline needs.
- In your
bitbucket-pipelines.yml, you setoidc: trueon any step that needs cloud access. Bitbucket generates a unique OIDC token and exposes it as the$BITBUCKET_STEP_OIDC_TOKENenvironment variable. - Your pipeline uses that token to assume the role and receive temporary credentials.
Setting Up OIDC with AWS
First, retrieve your OIDC configuration from Bitbucket. In your repository, go to Repository settings > Pipelines > OpenID Connect. Copy the Identity provider URL and Audience values.
Then, in the AWS IAM console:
- Navigate to Identity providers > Add provider.
- Select OpenID Connect, paste the Identity provider URL and Audience from Bitbucket, and click Get thumbprint to verify.
- Click Add provider.
- Create a new IAM role with Web identity as the trusted entity. Select the Bitbucket provider and audience you just created, and attach the permission policies your pipeline needs.
- Optionally, edit the role's trust policy to restrict access to a specific repository or deployment environment using the
subclaim.
Finally, update your pipeline to use OIDC:
image: amazon/aws-cli
pipelines:
default:
- step:
name: "Deploy to AWS with OIDC"
oidc: true
script:
- export AWS_REGION=us-east-1
- export AWS_ROLE_ARN=arn:aws:iam::123456789012:role/bitbucket-deploy-role
- export AWS_WEB_IDENTITY_TOKEN_FILE=$(pwd)/web-identity-token
- echo $BITBUCKET_STEP_OIDC_TOKEN > $(pwd)/web-identity-token
- aws s3 ls
Bitbucket also provides pre-built AWS Pipes that support OIDC natively. When using a Pipe, you pass the AWS_OIDC_ROLE_ARN variable instead of access keys:
pipelines:
default:
- step:
name: "Deploy to S3 with OIDC"
oidc: true
script:
- pipe: atlassian/aws-s3-deploy:1.1.0
variables:
AWS_DEFAULT_REGION: "us-east-1"
AWS_OIDC_ROLE_ARN: "arn:aws:iam::123456789012:role/bitbucket-deploy-role"
S3_BUCKET: "my-bucket"
LOCAL_PATH: "build"
OIDC is also supported for GCP, Azure, and HashiCorp Vault. Refer to Atlassian's documentation for provider-specific setup instructions.
For any pipeline that deploys to a cloud provider, OIDC should be the default approach. Only fall back to stored secrets when OIDC is not supported by the target service.
Third-Party Secret Providers
In late 2024, Atlassian introduced native support for third-party secret providers in Bitbucket Pipelines. This feature allows secrets to be injected from an external vault (such as HashiCorp Vault or AWS Secrets Manager) directly into a pipeline step's execution environment, without ever being stored within Bitbucket.
Unlike user-defined workspace and repository variables, third-party secrets are fetched from your vault only when a properly configured pipeline step runs. Logs automatically mask these variables, and on self-hosted runners, the secrets remain confined to your own network.
How It Works
The integration follows this flow:
- When a pipeline step with
oidc: trueis scheduled, Bitbucket generates an OIDC JWT token. - The runner sends a GET request to your secret provider's endpoint, including the OIDC token in the Authorization header.
- Your secret provider middleware validates the OIDC token using Bitbucket's JWKS endpoint.
- On successful validation, the provider returns the requested secrets to the runner.
- The secrets are injected as environment variables into the step's execution context.
Configuration
This feature requires you to build a small middleware service that bridges your secret store and the Bitbucket runner. Atlassian provides a sample Java application as a reference implementation.
For self-hosted runners, set the SECRET_PROVIDER_URI when starting the runner:
docker container run \ -e SECRET_PROVIDER_URI="http://secret.provider/endpoint" \ # ... other runner configuration
For cloud runners, add the secret provider endpoint in your workspace settings:
- Navigate to Workspace settings > Pipelines > Workspace variables.
- Add your secret provider endpoint in the provided field and click Add.
In your pipeline, enable OIDC on the steps that need third-party secrets. If a pipeline variable has the same name as a secret in your provider, the provider's value will replace it at runtime:
pipelines:
default:
- step:
name: "Build with third-party secrets"
oidc: true
script:
- echo "Building with secrets from external vault"
- ./build.sh
This approach is especially powerful for organizations that already use a centralized vault and want to avoid duplicating secrets into Bitbucket's variable storage.
The Limitations of Bitbucket’s Pipelines Approach
While Bitbucket's secrets capabilities have expanded significantly, there are still some practical limitations to be aware of:
- No automatic secret rotation. Bitbucket does not provide built-in tools for automatically rotating secrets stored as pipeline variables. You can delegate rotation to an external vault using the third-party secret provider integration or OIDC, but if you are storing secrets directly in Bitbucket, manual updates are required.
- Visibility restrictions. Once a secured variable is saved, its value cannot be viewed again. This ensures security but can be inconvenient if the value needs to be verified later. You can only overwrite it with a new value or delete it.
- Limited auditing for pipeline variables. Bitbucket provides workspace-level audit logs through Atlassian Guard (formerly Atlassian Access), which can track some administrative events. However, Bitbucket Pipelines variables themselves do not offer detailed change history showing exactly who modified a specific variable and when. Bitbucket Data Center has its own audit log with more granular tracking.
- Scalability challenges. As the number of repositories and secrets grows, managing variables across multiple repositories and environments can become cumbersome without a centralized system. There is no built-in way to sync or propagate a variable change across many repositories at once.
- Risk of exfiltration. Although Bitbucket automatically masks secured variables in build logs, any user with write access to a repository can modify the pipeline YAML to send variable values to an external endpoint. Use deployment variables combined with deployment permissions to limit who can access sensitive credentials.
- Secret scanning varies by platform. Bitbucket Data Center includes built-in secret scanning that is enabled by default, with customizable regex patterns and audit log alerts. For Bitbucket Cloud, secret scanning capabilities depend on your plan and whether you use Atlassian Guard. More advanced detection and prevention may require third-party tools such as GitGuardian or Soteri.
For teams with more complex requirements, a dedicated secrets manager like Infisical can provide centralized management, automatic rotation, detailed audit trails, and easier scalability across repositories and environments.
Using Infisical and Bitbucket
Infisical is an open-source secrets management platform that integrates with Bitbucket in two ways: pushing secrets into Bitbucket variables automatically (Secret Syncs), and pulling secrets into pipelines at runtime using the Infisical CLI.
Option 1: Secret Syncs (Push-Based)
With Infisical's Bitbucket Secret Sync, secrets stored in Infisical are automatically pushed to Bitbucket as repository-level or deployment environment-level variables. When you update a secret in Infisical, the change is automatically synced to Bitbucket.
To set up a Secret Sync:
- Navigate to your project's Integrations tab in Infisical, and click Add Sync.
- Select the Bitbucket tile and grant Infisical access to your Bitbucket account.
- Select the Infisical project environment, secret path, and the target Bitbucket workspace, repository, and optionally the deployment environment you want to sync secrets to.
- Click Create Integration.
Once created, your secrets will begin syncing automatically. Your pipeline YAML does not need any Infisical-specific configuration; it references the variables using standard $VARIABLE_NAME syntax just as with any other Bitbucket variable.
Option 2: CLI Injection (Pull-Based)
For more control over when and how secrets are fetched, you can use the Infisical CLI directly in your pipeline. This approach fetches secrets at runtime and injects them into the process environment without storing them in Bitbucket at all.
By using Infisical's OIDC Auth method together with Bitbucket Pipelines' built-in OIDC support, you can authenticate to Infisical without storing any long-lived credentials. Instead, Bitbucket generates a short-lived OIDC token for each pipeline step, and Infisical verifies that token directly. No Client ID or Client Secret needs to be stored in Bitbucket.
Step 1: Configure a Machine Identity
In Infisical, navigate to Organization Settings > Access Control > Identities and click Create identity. Give it a descriptive name (for example, "bitbucket-pipeline") and assign it an organization-level role.
Step 2: Configure OIDC Auth on the identity
Once the identity is created, you will be redirected to a page where you can manage it. Since the identity is configured with Universal Auth by default, you need to reconfigure it to use OIDC Auth instead. Press Edit in the Authentication section, remove the existing Universal Auth configuration, and add a new OIDC Auth configuration.
Configure the following fields using the values from your Bitbucket repository's OpenID Connect settings page (found under Repository settings > Pipelines > OpenID Connect):
- OIDC Discovery URL:
https://api.bitbucket.org/2.0/workspaces/YOUR_WORKSPACE/pipelines-config/identity/oidc - Issuer:
https://api.bitbucket.org/2.0/workspaces/YOUR_WORKSPACE/pipelines-config/identity/oidc - Subject: The subject (
sub) claim typically includes repository and step identifiers (for example:{REPO_UUID}:{ENVIRONMENT_UUID}:{STEP_UUID}). Verify the exact value by inspecting a real OIDC token from your pipeline. You can use a wildcard pattern to allow multiple repositories or steps, or leave it blank to skip subject validation. - Audiences: The audience value shown on the Bitbucket OpenID Connect settings page (formatted as
ari:cloud:bitbucket::workspace/YOUR_WORKSPACE_UUID).
Step 3: Add the identity to your project
Navigate to the Infisical project that contains the secrets you want to access. Go to Access Control > Machine Identities, click Add identity, select the identity you created, and assign it a project-level role with read access to secrets.
Take note of the identity's ID, which you will need in the pipeline configuration.
Step 4: Update your pipeline
Edit your bitbucket-pipelines.yml to enable OIDC and use the Infisical CLI with OIDC Auth. The key difference from other authentication methods is that you set oidc: true on the pipeline step and pass the Bitbucket-generated OIDC token ($BITBUCKET_STEP_OIDC_TOKEN) directly to the Infisical CLI:
image: atlassian/default-image:3
pipelines:
default:
- step:
name: Build application with secrets from Infisical
oidc: true
script:
- apt-get update && apt-get install -y curl
- curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash
- apt-get update && apt-get install -y infisical
- export INFISICAL_TOKEN=$(infisical login --method=oidc-auth --machine-identity-id=YOUR_IDENTITY_ID --oidc-jwt=$BITBUCKET_STEP_OIDC_TOKEN --silent --plain)
- infisical run --projectId=YOUR_PROJECT_ID --env=dev -- npm run build
Replace YOUR_IDENTITY_ID with the machine identity ID from Infisical and YOUR_PROJECT_ID with your Infisical project ID. The --env flag specifies which Infisical environment to pull secrets from (for example, dev, staging, or prod). The infisical run command fetches all secrets from the specified project and environment, then injects them as environment variables into the command that follows the -- separator.
With this configuration, no Infisical credentials are stored in Bitbucket at all. The authentication is entirely based on the short-lived OIDC token that Bitbucket generates for each pipeline step, which Infisical verifies using Bitbucket's public JWKS endpoint.
Each identity access token returned by Infisical has a configurable time-to-live (TTL), with a default of 7200 seconds. You can adjust this in the OIDC Auth configuration for the machine identity.
You can follow Infisical's end-to-end OIDC Auth documentation for additional configuration options, including how to restrict access by subject, audience, and custom claims.
Important: App Password Deprecation
Atlassian is transitioning Bitbucket Cloud from app passwords to API tokens. This change follows a phased timeline:
- Phase 1 (June 2025): Deprecation announced. Existing app passwords continue to work. Teams can begin transitioning to API tokens.
- Phase 2 (September 9, 2025): Creation of new app passwords is disabled. All new integrations must use API tokens.
- Phase 3 (June 9, 2026): All remaining app passwords are permanently disabled. Only API tokens will work for Bitbucket Cloud authentication.
API tokens offer improved security through expiry controls, scoped permissions, and better admin visibility. If your team uses app passwords for scripts, CI/CD tools, or third-party integrations that connect to Bitbucket, begin migrating to API tokens now.
To create an API token: navigate to Settings > Atlassian account settings > Security, then select Create and manage API tokens > Create API token with scopes. Assign the necessary Bitbucket permissions and set an appropriate expiry date. The token is displayed only once, so store it securely.
Protecting Sensitive Data in Bitbucket
Managing secrets effectively is essential for maintaining security across your development infrastructure. Whether you use Bitbucket's built-in variables, OIDC keyless authentication, third-party secret providers, or a dedicated platform like Infisical, the core objective remains the same: limit access and prevent exposure.
When using Bitbucket, remember to:
- Prefer OIDC over stored credentials for cloud provider authentication. This eliminates the need to store and rotate long-lived access keys.
- Choose the correct scope for each secret. Use deployment variables with deployment permissions for production credentials, repository variables for repo-specific configuration, and workspace variables only for truly shared values.
- Restrict write access to repositories that contain pipelines using sensitive secrets, since anyone with write access can potentially exfiltrate secured variables.
- Migrate from app passwords to API tokens before the June 9, 2026 deadline.
- Evaluate third-party secret provider integration if your organization already uses a centralized vault, to avoid duplicating secrets into Bitbucket.
Following these practices will help ensure that sensitive information stays protected while remaining accessible to authorized team members and automated workflows.

