Skip to content
Benchmarks

redact-secret · Report

GitHub App server-to-server token

GitHub App installation (server-to-server) token, prefixed ghs_.

  • GitHub
  • Detectors: github-token
  • Run 2026-10-07
  • Mode published · redact-secret 0.1.0-beta.14
  • Dossier verdictReady
  • Dossier evidence levelT1 · Provider-documented
  • Dossier researched2026-09-20

Research record

From credential-evidence snapshot-2026.10.06.4 · records at 77ce761 · schema 1.8.0. It describes the research on the format, not what any scanner or the product does, and not a support status.
  • Review stateDraft, not reviewed
  • Format revision2 · current
  • ResearchResearched
  • Researched2026-09-20

Format revisions

  • Revision 1 github:app-server-to-server-token@1historical · draft, not reviewed · superseded by @2
  • Revision 2 github:app-server-to-server-token@2current · draft, not reviewed · supersedes @1 · issued from 2026-04-27 · the family's current revision

5 events in the review history: 4 observed, 1 reviewed. Latest: observed on 2026-10-03 by automation, project maintainer. Project-maintained review is not independent validation. The family record at this release.

Format

Provider format research from credential-evidence snapshot-2026.10.06.4 · records at 77ce761 · schema 1.8.0.

What it looks like

Prefixes
ghs_
prefix (prefix)
ghs_ marks an installation access token for a GitHub App; the prefix is unchanged by the stateless format.
app-id (other)
Stateless form only: the APPID of ghs_APPID_JWT, followed by an underscore. Its alphabet and length are not documented.
jwt (body)
Stateless form only: a JWT signed with a GitHub-internal issuer, about 520 characters in total for the token, containing two dots. Clients must not parse or validate it.
opaque-body (body)
Stateful (opaque) form: no dots; the provider describes these tokens as 40 characters long.
Separators
_ · .
Length
min 36
Alphabet
other · A-Za-z0-9.-_
Checksum
Not documented for the stateless form. The 2021 CRC32 checksum in the last six characters of the opaque body is carried by contract revision 1 only and is not restated here.
Descriptive pattern
^ghs_[A-Za-z0-9.\-_]{36,}$

Parts are shown as recorded. Evidence classes belong to the facts below; no class is assigned to a part.

Format facts

  • Provider documented · stateless-rollout · current · observed 2026-10-03

    GitHub states that from 2026-04-27 it began a staged rollout of a stateless installation-token format, written ghs_APPID_JWT, for newly minted GitHub App installation tokens, that the ghs_ prefix is unchanged, and that existing installation tokens keep working until they expire. The rollout is stated for GitHub Enterprise Cloud and Data Residency, not GitHub Enterprise Server.

  • Provider documented · stateless-length-and-dots · current · observed 2026-10-03

    GitHub describes the stateless installation token as longer than the previous form (about 520 characters, varying with the data stored in it) and as a ghs_-prefixed JWT with two dots, and the stateful token as a short opaque string with no dots; it says to tell them apart by counting the dots after the ghs_ prefix. Two dots is consistent with the three-part JWS compact serialization used by RFC 7519 JWTs.

  • Provider documented · previous-form-40-characters · current · observed 2026-10-03

    GitHub warns that applications which expect installation tokens to be exactly 40 characters long may mishandle the new format, which states that the previous (stateful, opaque) form is 40 characters, that is ghs_ plus 36 characters.

  • Provider documented · recommended-regex · current · observed 2026-10-03

    GitHub recommends ghs_[A-Za-z0-9\.\-_]{36,} to match both the new and the current format, and asks that any validating regex handle additional underscores and the presence of a JWT. The page records an editor's note dated 2026-05-26 that updated this regex guidance, so earlier wording of it differed.

  • Provider documented · per-request-override-header · current · observed 2026-10-03

    GitHub provides a temporary request header, X-GitHub-Stateless-S2S-Token, on POST /app/installations/:installation_id/access_tokens: enabled returns a stateless token, disabled a stateful one, absent means normal rollout, and any other value is ignored. The header is temporary: the 2026-05-15 entry said it would stop being respected at a deprecation point to be announced, after which eligible apps always receive stateless tokens, and the 2026-10-02 entry sets that date at 2026-11-30 (see rollout-complete-header-deprecation).

  • Provider documented · rollout-complete-header-deprecation · current · observed 2026-10-04

    GitHub states, in a changelog entry dated 2026-10-02, that the staged rollout begun on 2026-04-27 is complete: by default all newly minted GitHub App installation tokens are now in the stateless ghs_APPID_JWT format, about 520 characters long instead of 40, with the ghs_ prefix, one-hour expiration and the installation access token endpoint unchanged, and tokens minted earlier working until they expire. It says the temporary X-GitHub-Stateless-S2S-Token header will be deprecated on 2026-11-30, after which GitHub no longer respects it and all eligible apps always receive stateless tokens. Until that date the header value disabled is still described as available (in the 2026-05-15 entry), so the opaque form can still be minted on request until then.

  • Provider documented · rollout-phase-plan · historical · observed 2026-10-04

    In its 2026-04-24 notice GitHub planned the staged rollout in two phases: 2026-04-27 to mid-May 2026 for the GitHub Actions GITHUB_TOKEN and the installation tokens of GitHub's first-party featured integrations, then mid-May to late June 2026 for all GitHub App installation tokens, with a brownout period before broad enablement. These are planned windows from the announcement; the 2026-10-02 entry states only that the rollout is complete, not the dates of each phase or of any brownout. The stateless format applies to installation server-to-server tokens including the Actions GITHUB_TOKEN; user-to-server tokens are not in scope in these entries.

  • Provider documented · storage-length-lower-bound-only · current · observed 2026-10-04

    GitHub's guidance on storage is a lower bound, not an upper bound on the token: database columns for installation tokens should fit at least a 520 character string (2026-04-24 entry), and columns, secret stores or environment variables with a fixed or small maximum, and proxies that truncate or reject long Authorization headers, are named as things to check (2026-10-02 entry). Neither states a maximum token length, so a stateless token longer than about 520 characters is not excluded or confirmed.

  • Unresolved · app-id-and-jwt-contents-undocumented · current · observed 2026-10-03

    The provider documents neither the alphabet nor the length of the APPID segment, nor whether every stateless token carries it, and says the JWT contents are not for clients to depend on. The recommended regex also accepts a ghs_ value without an APPID segment, so the APPID-less shape is described by the regex but not by the ghs_APPID_JWT notation.

Open questions

  • github:app-server-to-server-token@2#app-id-segment-grammar · raised 2026-10-03

    What are the alphabet and length of the APPID segment of ghs_APPID_JWT, and is the segment present in every stateless token?

  • github:app-server-to-server-token@2#stateless-length-bounds · raised 2026-10-03

    Is there a documented upper bound or exact range for the stateless token length beyond "about 520 characters, varying with its contents"? The 2026-10-02 entry and the storage guidance (columns must fit at least 520 characters) give no maximum.

  • github:app-server-to-server-token@2#opaque-form-checksum-current · raised 2026-10-03

    Does the 2021 CRC32 checksum still apply to the opaque (stateful) form, and does any equivalent apply to the stateless form?

Benchmark dossier notes

From the provider dossier, as written. The evidence level above says how well the format is backed; a fact the dossier does not record is not shown.
Basis
prefix and role from the token-formats page; body from GitHub's 2021-04-05 token-format post; contracted per family in #517 (T1; body tool-corroborated). The #223 pass notes that GitHub announced a new ghs_APPID_JWT installation-token format (variable length, about 520 characters, rollout from 2026-04-27), which belongs to this family and not to the fine-grained one.

In this benchmark

Fixture rows on the current run. Counts are for redact-secret in published · redact-secret 0.1.0-beta.14 mode.
Fixtures
42
Left readable
0
Redacted too much
0
False alarms
0

42 fixtures: 29 expect a redaction, 12 must stay quiet, 1 record project policy. See every row

redact-secret fixture counts by evidence level
Evidence levelFixturesLeft readableToo muchFalse alarms
T1Provider-documented32000
T2Tool-corroborated3000
T3Project policy4000
T0Pending review3000

Every scanner on the same fixtures

In run order. Counts are what each scanner recorded on this family's fixtures, whichever rules it has; a scanner with no rule for the family has nothing to report on it.

Counts per scanner on this family's fixtures
ScannerFixturesLeft readableToo muchFalse alarms
flare-redactRuntime library · 1.6.1 · Published npm package · secrets-only (pii, generic_assignment disabled) · JavaScript engine1 rule targets it42620
gitleaksRepository scanner · 8.30.1 · Directory scan · default rules1 rule targets it42800
redact-secretProduct measured here · 0.1.0-beta.14 · Published npm package · default detectors1 detector mapped42000
trufflehogRepository scanner · 3.97.4 · Filesystem scan · verification disabled1 rule targets it422001

Benchmark dossier questions

Things the sources do not settle. They are listed so nobody reads them as settled.
Open caveat
Only the prefix and token role are provider-documented; the 36-character body follows GitHub's 2021-04-05 token-format post (36-byte body, CRC32 in the last six characters), and core does not verify the checksum.

Scanner rules for this family

Mapped by hand (reviewed 2026-09-30) from each scanner's pinned rule file, never from what a scanner found on the fixtures.
Peer scanner rules that target this family
ScannerRuleWhat the rule matches
flare-redact · rules 1.6.1github_tokenghp_, gho_, ghu_, ghs_, ghr_ + 36 or github_pat_ + 82 characters
gitleaks · rules 8.30.1github-app-tokenghu_ or ghs_ + 36 alphanumerics
openredaction · rules 1.1.5GITHUB_TOKENghp_, gho_, ghu_, ghs_ or ghr_ + 36 or more characters
trufflehog · rules 3.97.4github/v2ghp_, gho_, ghu_, ghs_, ghr_ or github_pat_ + 36-255 characters
42 of 42 rows

Fixtures in this family

42 rows, redact-secret's outcome on each. Rows that need a look come first (0), then the rest in corpus order. Choose "Every scanner" to see each scanner's outcome for the same rows.
Fixtures in GitHub App server-to-server token
FixtureKind and evidenceredact-secret
installation-token-lifetime-noteenvironment-and-test-values-authored · app-installation-token-with-one-hour-lifetime-noteProject policyT3 · Project policyRedacted
github-token-short-body-35-twingithub · wrong-lengthMust not flagT2 · Tool-corroborated · twinQuiet
add-mask-literal-argumentgithub-actions-workflow-commands-authored · workflow-command-literal-credential-in-command-textMust redactT1 · Provider-documentedRedacted
base-tokengithub-actions-workflow-commands-authored · workflow-command-literal-credential-in-command-textMust redactT1 · Provider-documentedRedacted
env-file-echogithub-actions-workflow-commands-authored · workflow-command-literal-credential-in-command-textMust redactT1 · Provider-documentedRedacted
multiline-record-eof-delimitergithub-actions-workflow-commands-authored · workflow-command-file-multiline-record-valueMust redactT1 · Provider-documentedRedacted
multiline-record-guid-delimitergithub-actions-workflow-commands-authored · workflow-command-file-multiline-record-valueMust redactT1 · Provider-documentedRedacted
multiline-record-written-by-brace-groupgithub-actions-workflow-commands-authored · workflow-command-file-multiline-record-valueMust redactT1 · Provider-documentedRedacted
output-file-echogithub-actions-workflow-commands-authored · workflow-command-literal-credential-in-command-textMust redactT1 · Provider-documentedRedacted
base-opaquegithub-installation-token-authored · opaque-installation-token-forty-characters-literalMust redactT1 · Provider-documentedRedacted
base-stateless-agithub-installation-token-authored · stateless-jwt-installation-token-literalMust redactT1 · Provider-documentedRedacted
base-stateless-bgithub-installation-token-authored · stateless-jwt-installation-token-literalMust redactT1 · Provider-documentedRedacted
projection-opaque-crlfgithub-installation-token-authored · opaque-installation-token-forty-characters-literalMust redactT1 · Provider-documentedRedacted
projection-opaque-envgithub-installation-token-authored · opaque-installation-token-forty-characters-literalMust redactT1 · Provider-documentedRedacted
projection-opaque-jsongithub-installation-token-authored · opaque-installation-token-forty-characters-literalMust redactT1 · Provider-documentedRedacted
projection-stateless-a-authorizationgithub-installation-token-authored · stateless-jwt-installation-token-literalMust redactT1 · Provider-documentedRedacted
projection-stateless-a-crlfgithub-installation-token-authored · stateless-jwt-installation-token-literalMust redactT1 · Provider-documentedRedacted
projection-stateless-a-git-urlgithub-installation-token-authored · stateless-jwt-installation-token-literalMust redactT1 · Provider-documentedRedacted
projection-stateless-a-jsongithub-installation-token-authored · stateless-jwt-installation-token-literalMust redactT1 · Provider-documentedRedacted
projection-stateless-a-korean-emojigithub-installation-token-authored · stateless-jwt-installation-token-literalMust redactT1 · Provider-documentedRedacted
projection-stateless-b-envgithub-installation-token-authored · stateless-jwt-installation-token-literalMust redactT1 · Provider-documentedRedacted
ghs-1github · documented-format-literalMust redactT1 · Provider-documentedRedacted
ghs-2github · documented-format-literalMust redactT1 · Provider-documentedRedacted
ghs-3github · documented-format-literalMust redactT1 · Provider-documentedRedacted
github-token-ghs-plaingithub · documented-format-literalMust redactT1 · Provider-documentedRedacted
github-token-ghs-plain-twingithub · wrong-lengthMust not flagT2 · Tool-corroborated · twinQuiet
github-token-ghs-unicode-crlfgithub · documented-format-literalMust redactT1 · Provider-documentedRedacted
github-token-ghs-unicode-crlf-twingithub · wrong-lengthMust not flagT2 · Tool-corroborated · twinQuiet
github-token-installation-clone-urlgithub · documented-format-literalMust redactT1 · Provider-documentedRedacted
github-token-shape-4-baregithub · documented-format-literalMust redactT1 · Provider-documentedRedacted
github-token-shape-4-quotedgithub · documented-format-literalMust redactT1 · Provider-documentedRedacted
github-token-shape-4-unicode-crlfgithub · documented-format-literalMust redactT1 · Provider-documentedRedacted
expression-in-environment-file-echogithub-actions-workflow-commands-authored · workflow-command-reference-and-masked-value-in-place-of-credentialMust not flagT1 · Provider-documentedQuiet
runner-mask-in-log-linegithub-actions-workflow-commands-authored · workflow-command-reference-and-masked-value-in-place-of-credentialMust not flagT1 · Provider-documentedQuiet
unset-secret-expanded-to-empty-valuegithub-actions-workflow-commands-authored · workflow-command-reference-and-masked-value-in-place-of-credentialMust not flagT1 · Provider-documentedQuiet
variable-reference-in-add-mask-and-outputgithub-actions-workflow-commands-authored · workflow-command-reference-and-masked-value-in-place-of-credentialMust not flagT1 · Provider-documentedQuiet
base-ids-jsongithub-installation-token-authored · github-app-and-installation-ids-in-jsonMust not flagT3 · Project policyQuiet
base-no-app-idgithub-installation-token-authored · installation-token-without-app-id-segmentPending reviewT0 · PendingUnscored
base-prose-notationgithub-installation-token-authored · installation-token-notation-and-header-name-in-proseMust not flagT3 · Project policyQuiet
mutation-incomplete-header-onlygithub-installation-token-authored · installation-token-with-incomplete-jwt-segmentsPending reviewT0 · Pending · twinUnscored
mutation-incomplete-no-signaturegithub-installation-token-authored · installation-token-with-incomplete-jwt-segmentsPending reviewT0 · Pending · twinUnscored
twin-body-35github-installation-token-authored · installation-token-body-shorter-than-documented-minimumMust not flagT3 · Project policy · twinQuiet

Sources

Researched 2026-09-20.

Documentation and code

  • docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-authentication-to-github#githubs-token-formats

Research log

Other GitHub families