Safeguard
Application Security•

How do you give GitLab CI jobs only the access they need?

Use the job token allowlist, keep cross-project push off unless needed, and swap personal access tokens for ID tokens so a hijacked job reaches little.

Safeguard Security Team
5 min read

Give GitLab CI jobs least privilege by keeping the job token allowlist limited to projects that truly need access, leaving Git push by job token off by default, and replacing personal access tokens with short-lived job or ID tokens. A stolen token should unlock one project for minutes, not a whole group.

What can a job token do?

When a job is about to run, GitLab generates a unique token and exposes it as CI_JOB_TOKEN. It works only while the job runs and is revoked afterwards. It inherits the access level of the user who triggered the pipeline, but reaches fewer resources than a personal access token. The documentation lists the allowed areas: package and container registries, job artifact downloads, deployments, environments, releases, and a handful of read endpoints for branches, tags, commits and merge requests.

That list is the useful part for a threat model. If a job token leaks, an attacker gets what the triggering user could do within those endpoints, for as long as the job is alive.

Who is allowed to use a token against my project?

By default, the allowlist for a project contains only itself. Another project can use its job token against yours only if you add it, and adding a group covers every project in that group and its subgroups, including ones created later. The limit is 200 groups and 200 projects, counted separately.

Two details are easy to miss. First, allowlisting does not grant extra permissions: the person who started the pipeline in the other project still needs rights on yours. Second, for public or internal projects, some resources such as artifacts, registries and the repository can be fetched by jobs outside the allowlist unless you set those features to visible to project members only.

Self-managed administrators can enforce the allowlist for every project. The documentation warns that disabling it is a security risk and should be done only for testing.

Should jobs push code with a job token?

Pushing with a job token is controlled by a setting that is off by default. GitLab also documents a cross-project push option, introduced to avoid long-lived access tokens in GitOps and submodule tagging. It needs several switches to be true at once, including the allowlist and a Developer role for the triggering user.

The docs carry a specific warning: do not enable these on projects configured as pull mirrors, especially when pipelines run on mirror updates, because an upstream owner could try to use the token to push commits into your mirror. If you turn the feature on, treat the target project as one whose pipelines you fully trust.

Where do ID tokens fit?

For cloud and secrets providers, a job can request an OpenID Connect ID token with the id_tokens keyword. GitLab advises writing cloud trust policies with stable identifiers such as namespace_id and project_id next to path-based claims, because a project path can be reused by a different project later. GitLab even blocks token issuance when a path in the subject claim was previously used by another project, and tells you to rebuild the subject around the project ID.

A constructed example

A platform team keeps a personal access token from a former engineer in group settings so the release job can tag other repositories. When that engineer leaves, nobody rotates it. Replacing it means three changes: the target repositories add the release project to their allowlist, the release job uses its job token, and the old token is revoked. Each target now has a short list of who can reach it, visible in settings.

What to do

  1. Open Settings, CI/CD, Job token permissions on each project and read the allowlist.
  2. Remove groups that were added for convenience and add specific projects instead.
  3. Check that public and internal projects hide registry and artifact access from non-members where that matters.
  4. Leave Git push by job token disabled unless a workflow demands it, and never on pull mirrors.
  5. Replace personal access tokens in pipelines with job tokens or ID tokens.
  6. Tie cloud trust policies to project ID and protected refs.
  7. Review runner configuration so one job cannot read another job's token.

Safeguard policy gates can enforce pipeline checks alongside this, as shown in the pull request gate demo.

Quick check

Does adding a project to the allowlist give its members new rights?

No. The user who starts the pipeline still needs the permission on the target project. The allowlist only decides whose job tokens are accepted.

Why bind trust policies to project ID?

Paths can be reused by a different project after a rename or delete, while the numeric ID stays unique to the original project.

Sources

Last reviewed: 18 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.