GitHub is rolling out a new stateless format for ghs_ installation tokens starting April 27, 2026.
The current detection regex will silently miss all tokens in the new format.
Reference: https://github.blog/changelog/2026-04-24-notice-about-upcoming-new-format-for-github-app-installation-tokens/
What is changing
| Property |
Old format |
New format |
| Structure |
ghs_<alphanumeric> |
ghs_<APPID>_<JWT> |
| Length |
Fixed 36 chars |
~520 chars (variable) |
| Character set |
[0-9a-zA-Z] |
[0-9a-zA-Z_] |
Rollout timeline:
- April 27 – mid-May 2026:
GITHUB_TOKEN, Dependabot, Slack/Teams
- Mid-May – late June 2026: All GitHub App installation tokens
Currently affects GitHub Enterprise Cloud and Data Residency only; regular github.com is not
affected yet.
Why the current regex fails
Current: (ghu|ghs)_[0-9a-zA-Z]{36}
{36} — new tokens are ~520 chars; exact-length match will never fire.
[0-9a-zA-Z] — new format contains an internal _ separator (ghs_<APPID>_<JWT>).
Suggested implementation
Update the ghs_ branch to accept variable length and underscores while keeping ghu_ strict:
Regex: MustCompileWithoutWordPrefix(`(?P<secret>(?:ghu_[0-9a-zA-Z]{36}|ghs_[0-9a-zA-Z_]{36,}))`),
Or add a dedicated rule for the new format to keep IDs stable:
{
ID: "github-app-installation-token",
Category: CategoryGitHub,
Title: "GitHub App Installation Token (stateless format)",
Severity: "CRITICAL",
Regex: MustCompileWithoutWordPrefix(`(?P<secret>ghs_[0-9a-zA-Z]{1,}_[0-9a-zA-Z_]{100,})`),
SecretGroupName: "secret",
Keywords: []string{"ghs_"},
},
Acceptance criteria
Test cases
// synthetic token matching new format ghs_<APPID>_<JWT> — must match
"ghs_A1B2C3_eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3NDU2MDAwMDAsImV4cCI6MTc0NTYwMzYwMH0.signature"
// old-format ghs_ token — must still match
"ghs_16C7e42F292c6912E7710c838347Ae178B4a"
// old-format ghu_ token — must still match
"ghu_16C7e42F292c6912E7710c838347Ae178B4a"
GitHub is rolling out a new stateless format for
ghs_installation tokens starting April 27, 2026.The current detection regex will silently miss all tokens in the new format.
Reference: https://github.blog/changelog/2026-04-24-notice-about-upcoming-new-format-for-github-app-installation-tokens/
What is changing
ghs_<alphanumeric>ghs_<APPID>_<JWT>[0-9a-zA-Z][0-9a-zA-Z_]Rollout timeline:
GITHUB_TOKEN, Dependabot, Slack/TeamsCurrently affects GitHub Enterprise Cloud and Data Residency only; regular github.com is not
affected yet.
Why the current regex fails
Current:
(ghu|ghs)_[0-9a-zA-Z]{36}{36}— new tokens are ~520 chars; exact-length match will never fire.[0-9a-zA-Z]— new format contains an internal_separator (ghs_<APPID>_<JWT>).Suggested implementation
Update the
ghs_branch to accept variable length and underscores while keepingghu_strict:Or add a dedicated rule for the new format to keep IDs stable:
{ ID: "github-app-installation-token", Category: CategoryGitHub, Title: "GitHub App Installation Token (stateless format)", Severity: "CRITICAL", Regex: MustCompileWithoutWordPrefix(`(?P<secret>ghs_[0-9a-zA-Z]{1,}_[0-9a-zA-Z_]{100,})`), SecretGroupName: "secret", Keywords: []string{"ghs_"}, },Acceptance criteria
ghs_tokens (~520 chars, with internal_) are detected with severity CRITICAL.ghs_[0-9a-zA-Z]{36}andghu_[0-9a-zA-Z]{36}tokens remain detected.Test cases