Skip to content
DevOps Society

Your GitLab Issue Email Address Is a Credential: One Leak Lets Anyone Push to main

Aikido's research shows GitLab's create-by-email address is an account-wide, non-expiring token that walks past protected branches and IP allowlists. How to audit your exposure.

Published your local timeupdated

Your GitLab Issue Email Address Is a Credential: One Leak Lets Anyone Push to main

GitLab will give you an email address that turns a message into an issue or a merge request, and it presents it the way it presents any other convenience feature. Plenty of open source maintainers paste that address straight into a README so users can file bugs without signing up. Aikido Security researcher Joe Leon published work on 23 September 2026 showing that the address is a GitLab incoming email token wearing a convenience-feature costume: account-wide, non-expiring, and sufficient to land a commit on a protected branch from an IP your allowlist has never heard of.

This piece covers what the token actually grants, why the two controls most teams point at during an audit don't hold against it, and how to work out whether your own address is already sitting in a public file.

Anatomy of a GitLab incoming email token

The address Leon dissected looks like this:

incoming+<project-path>-<project-id>-glimt-XXXXXXXXXXXXXX-issue@incoming.gitlab.com

Everything before glimt- reads like scoping: a project path, a project ID, apparently a per-project inbox. It isn't. The glimt- string is the GitLab incoming email token, and per Leon's research it belongs to the account, not the project. It doesn't expire on its own, and it carries whatever permissions the account holds. A Guest's address is an annoyance. A Maintainer's address is a write credential to everything that Maintainer can write to.

Which matters, because the maintainer who pastes the address into a README is usually the person with the most access.

GitLab email to merge request is a code path, not a comment box

Most people who have seen the feature assume it creates issues. It also creates merge requests, and that is where it stops being a support convenience. Leon's demonstration sends an email whose body carries a Git patch. GitLab applies the patch and opens the merge request. If the patch modifies .gitlab-ci.yml, GitLab runs the pipeline it describes, which is the attacker's pipeline running with the project's runners and the project's variables.

Commits arriving this way can land on any branch, including protected branches like main.

An email carrying a patch sailing past a closed perimeter gate and a lowered barrier into a server rack where a pipeline has started running

From that single foothold, Leon's write-up lists the rest: pull source out of private projects, reach CI/CD variables and pipeline secrets, read confidential issues by driving the /move quick action, and pick up a CI_JOB_TOKEN for lateral movement into other projects the account can reach. That last one is the GitLab supply chain problem in miniature, because the blast radius stops being one repository and becomes whatever that account's job tokens can touch.

Protected branch bypass and the GitLab IP allowlist both fold

Two controls come up in nearly every code-security conversation with an auditor: source is only reachable from our network, and nothing reaches main without review. This path walks around both.

The GitLab IP allowlist fails because mail is not an HTTP request from a client you control. Leon demonstrated pushing into a private repository sitting behind an IP allowlist using only the email route. The allowlist never sees a connection to evaluate. Protected branches fail for the plainer reason that the token inherits the sender's rights; if the account can push to main, so can the address.

Neither is a bug in the allowlist or in branch protection. It's a second, lower-profile ingress path that those controls don't sit on. Treating them as a hard perimeter for code push is the mistake, and a common one. It is the same category of assumption behind long-lived credentials that outlived the control watching them.

What it grants versus what teams assume

Assumption

Reality per Aikido's research

The address is scoped to the project named in it

The glimt- token is account-wide; the project path is not the boundary

It only files issues

It also creates merge requests from emailed Git patches

It expires or rotates like a PAT

No expiry; valid until someone resets it by hand

Worst case is spam issues

Arbitrary .gitlab-ci.yml execution, secret access, source exfiltration

Our IP allowlist covers code ingress

Incoming email bypasses IP restrictions entirely

Protected branches stop unreviewed commits on main

Commits can land on protected branches via this path

The permission level of the leaker doesn't matter much

It's the whole story. The token inherits that account's access

We can turn it off per user

No per-user toggle; self-managed admins can only disable it instance-wide

"Working as intended" is a defensible position and still a problem

Leon reported this through HackerOne around May and June 2026. GitLab closed it as intended behaviour, on the reasoning that a leaked token is a leaked token. What GitLab shipped afterwards was documentation and UI work: a merge request titled "Align incoming email token capability across UI and docs" removed the claim that the token "cannot be used to access any other data", added "and merge requests" to the UI description, and documented that incoming email bypasses IP restrictions. The mechanism itself is unchanged. Nothing here is a patch, and you shouldn't read it as one.

The position is arguable. The token is a credential, GitLab calls it one in its own settings, and no vendor can stop you publishing your credentials. The failure is one of presentation and habit. Credentials get a mental category: you don't paste a PAT into a README, you don't screenshot it in a support thread, and your scanners look for its prefix. This one arrives as an email address inside a panel that reads like a mailing list feature, so it lands in the wrong category, and everything downstream follows from that.

Leon's preferred fix is narrower than an off switch: require the sender address to match the address on the GitLab account. That kills the anonymous-attacker version of this outright while leaving the feature working for the people it was built for. Dark Reading reports GitLab is considering it; Dark Reading also contacted GitLab for comment and got no response by press time.

This affects GitLab.com accounts and self-managed instances with incoming email enabled. GitLab Dedicated is reportedly unaffected, though unconfirmed.

How these addresses get out

Leon found roughly a dozen incoming email addresses published on purpose, in READMEs and support files of open source projects, by maintainers who wanted users to be able to file issues by email. Those are the deliberate leaks. The accidental ones are more numerous and harder to find: ticket exports, mail archives and mailing list threads that quote full headers, pastes into Slack and Jira, and shared-inbox forwarding rules written by someone who left two years ago.

A single email address copied from a settings panel into a document, a stack of exported records, an archive roll and a chat panel

The redeeming detail is the fixed glimt- prefix, which makes the token findable by pattern the way gho_ or AKIA are. Aikido added detection for glimt- prefixed tokens and custom self-managed variants to its Betterleaks scanner. If your own scanner has a custom-pattern facility, this is a five-minute rule worth adding, and worth wiring into the pre-merge gate rather than a nightly report, along the lines of secret scanning that blocks the merge instead of filing a ticket about it.

Audit your own exposure

Start with code, including history, because the README that carried the address in 2023 still exists in the object store:

# Working trees under one directory
rg -n --hidden -g '!.git/*' -e 'incoming\+' -e 'glimt-' ~/src

# Full history of one repo, where old READMEs and support docs hide
git rev-list --all | xargs -n 100 git grep -nI -e 'incoming+' -e 'glimt-' | head -50

GitLab wikis are separate Git repositories and don't come down with a normal clone:

git clone git@gitlab.com:your-group/your-project.wiki.git /tmp/wiki
git -C /tmp/wiki grep -nI -e 'incoming+' -e 'glimt-'

Then the non-code places, where most of the real exposure lives. Support exports, mailbox archives, chat dumps:

grep -rIn --include='*.csv' --include='*.json' --include='*.eml' --include='*.mbox' \
  -e 'incoming+' -e 'glimt-' ./exports

CI job logs deserve a pass of their own, because a token can reach them without anyone pasting it anywhere. A script that echoes an issue's reply-to address, or a debug step that dumps the environment, is enough:

curl -sS --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "https://gitlab.com/api/v4/projects/$PROJECT_ID/jobs/$JOB_ID/trace" \
  | grep -E 'incoming\+|glimt-'

Loop it over recent jobs in your highest-value projects; log retention caps how far back it's useful. Better as a permanent pipeline check than a one-off sweep. See our walkthrough of wiring security checks into CI/CD for where it fits.

If you find one, reset the GitLab incoming email token in your user settings, where GitLab surfaces it in the personal access token area. Budget for the breakage: the old address dies, so published instructions, saved contacts and mail rules pointing at it stop working. On self-managed, an admin can disable incoming email at the instance level. That's the only genuine off switch, and it removes the feature for everyone.

An honest read on severity

This needs your address to leak first. There's no CVE, no scannable internet-wide exposure, and nothing here that spreads on its own. It is not a drop-everything incident.

It is a check-your-own-exposure-this-week bug, and it earns that week on the shape of the failure rather than its reach: the thing that leaks is trivially leakable, it never expires, nobody treats it as a secret, and the impact ceiling is CI/CD execution with a Maintainer's rights. That combination is how a CI/CD token leak turns into a bad quarter, and it's why this belongs in the same bucket as the recent GitLab and GitHub CI changes worth scheduling time for rather than in a backlog.

Checklist for this week

  1. Grep every repository's working tree and full history for incoming+ and glimt-. Include wikis, which clone separately.

  2. Grep support ticket exports, mailbox archives and chat history dumps for the same two strings.

  3. Spot-check CI job traces in your highest-value projects for either pattern.

  4. Add a glimt- custom pattern to whatever secret scanner gates your merges, and to any self-managed prefix your instance uses.

  5. Reset the GitLab incoming email token for every account that has ever published or pasted its address, starting with Owners and Maintainers.

  6. Delete or replace published addresses in READMEs and support docs. If a project genuinely needs email intake, route it through a shared support inbox owned by a low-privilege service account, not a Maintainer.

  7. Self-managed: decide deliberately whether incoming email stays on, and write down who made that call.

  8. Remove "IP allowlisted" from the list of controls you claim as a hard boundary for code push, in your threat model and in your audit answers.

Decision rule: any string that grants access, never expires, and has no owner recorded anywhere should be rotated on the day you notice it, not the day you can prove it leaked. If you can't name who resets a credential and what breaks when they do, you don't control it. More on credential blast radius in our security coverage.

Written by

DevOpsSociety Editorial Team

Editorial Team

The DevOpsSociety Editorial Team covers DevOps, cloud infrastructure, Kubernetes, AI infrastructure, platform engineering, cybersecurity, FinOps, and modern engineering practices. We publish practical insights, technical guides, architecture analysis, and research for engineers and technology leaders.

More from DevOpsSociety
The Infrastructure Briefing

Get the infrastructure briefing.

Practical DevOps, cloud, AI infrastructure and engineering insights, delivered weekly. Read by engineers and engineering leaders.

No spam. Unsubscribe anytime.