GitHub App 安装令牌改成无状态格式:长度从 40 位涨到约 520 位,11 月 30 日前要清掉覆盖头

GitHub App 安装令牌无状态格式已全量切换:前缀仍是 ghs_,长度从 40 位涨到约 520 位;权限与端点不变,但硬编码长度校验、存储列宽、长 Authorization 头和脱敏规则都会出问题。

用 Apifox,节省研发团队的每一分钟

GitHub App 安装令牌改成无状态格式:长度从 40 位涨到约 520 位,11 月 30 日前要清掉覆盖头

免费使用 Apifox

相关推荐

最新文章

API

一体化协作平台

API 设计

API 文档

API 调试

自动化测试

API Mock

API Hub

立即体验 Apifox
目录

GitHub 在 2026 年 10 月 2 日宣布,2026 年 4 月 27 日开始的 GitHub App 安装令牌无状态格式切换已经全量完成:此后新签发的安装令牌默认使用 ghs_APPID_JWT 格式。令牌前缀仍是 ghs_,但长度从 40 个字符增长到约 520 个字符;权限、仓库范围、一小时过期时间和 installation access token 的 REST 端点都不变。为测试新格式而引入的 X-GitHub-Stateless-S2S-Token 请求头,将在 2026 年 11 月 30 日不再被尊重。

GitHub App 安装令牌旧格式 40 字符与新格式约 520 字符的对比,以及四类需要核对的代码
编辑绘制:按 GitHub Changelog(2026-10-02)公布的信息整理的新旧格式对比与迁移核对清单。

这类改动通常不会让代码报错,它让代码以很奇怪的方式坏掉。令牌还是那个令牌,权限也没变,唯一变的是它的长度——而"长度固定为 40"这个假设,在集成代码里往往以断言、正则、字段宽度和脱敏规则四种形式同时存在。

发生了什么:令牌变成自包含,长度翻了一个数量级

按 GitHub 的说明,无状态格式的含义是令牌本身携带应用与 JWT 信息,GitHub 在签发和校验时不再需要额外的服务端状态,因此签发与校验更快,API 也更可靠。这解释了为什么长度会涨到约 520 个字符:信息被放进了令牌里。

GitHub 明确列了四项不变:令牌权限、仓库范围限定、一小时过期时间,以及 installation access token 的 REST API 端点。这意味着调用方式的代码路径完全不用改——请求还是打到同一个端点,拿到的还是同样权限的令牌。切换前签发的令牌在自身过期前仍然有效。

那个过渡用的 X-GitHub-Stateless-S2S-Token 请求头,是当初为了让开发者按需测试新格式而加的。GitHub 给了明确时间表:2026 年 11 月 30 日起将不再尊重这个头,符合条件的应用一律拿到无状态令牌。给的建议是,在确认应用和流水线同时兼容两种格式之后,就把它从生产代码里删掉,不必等到最后期限。

一个真实的损坏场景

假设一个团队维护一个内部部署网关,所有 CI 和内部服务都通过它访问 GitHub API。令牌在网关里会做三件事:一是校验格式,用一条断言确认以 ghs_ 开头且长度等于 40;二是写进一张审计表,字段定义是 varchar(64);三是写日志,用一条正则把 ghs_ 开头的密钥替换成掩码。

切换之后,这三件事会以三种不同方式坏掉。断言让网关直接拒绝新令牌,流水线在鉴权这一步就断了,报错看起来像权限问题而不是格式问题;审计表因为长度不够,写入被截断或直接报错,令牌被写进去半截;脱敏正则如果只匹配旧的定长模式,新令牌可能有一大段没被掩住,然后被完整写进日志。

第三种最危险,因为它不报错。流水线正常跑,审计表正常写,只是某天有人翻日志,看到一个 520 字符的字符串躺在那儿。安装令牌是有仓库权限的凭据,按 GitHub 的说明它也有一小时有效期——一小时对自动化来说足够做很多事。

修复顺序上,先让网关能接受长令牌(去掉长度断言、把脱敏改成按前缀匹配而不是按定长匹配),再处理存储(把字段放宽或改造存储方式),最后把 X-GitHub-Stateless-S2S-Token 头从生产代码里删掉。反过来做会先遇到一堆看起来像权限故障的错误。

为什么这条改动值得单独立项

第一个原因是它的隐蔽性。任何"我验证过格式没问题"的代码,在格式变化时都会从"验证"变成"阻断",而错误信息通常描述的是后果(鉴权失败、写入失败、长度超限),不是原因(格式变了)。团队在排查时会先怀疑凭据过期、权限配错、网络问题,最后才想到令牌变长了。

第二个原因是它的破坏面是分散的。写下 40 这个数字的人,和在网关里写脱敏正则的人,在数据库里定义字段宽度的人,通常不是同一个人,甚至不在同一个团队。这类改动没有单一的责任人,需要一次有名单的排查。

第三个原因是时间线是硬的。2026 年 11 月 30 日之后,覆盖头不再被尊重,所有符合条件的应用都走新格式。也就是说,靠这个头"暂时留在旧格式"不是一个可以长期依赖的退路,它只是一个到 11 月 30 日为止的测试窗口。团队要么现在就改完,要么在那个日期被动承接同一批问题。

限制、边界与人该在哪里接管

GitHub 给的是方向,不是清单。它点名了四类需要留意的地方——把长度硬编码成 40 的校验、存储介质(数据库列、secret store、环境变量)的容量、会截断或拒收超长 Authorization 头的代理与中间件、以及只按旧模式匹配的日志与脱敏规则——但这些具体在哪里,只有你自己的代码库知道。

另一个边界是"切换前签发的令牌仍然有效"。这一条会让排查变得模糊:如果你在灰度窗口里看到一部分调用成功、一部分失败,那不是随机故障,而是新旧两种令牌同时在流。核对时要按令牌的签发时间分组看,而不是当成偶发问题重试。

人该接管的地方是三处。第一,脱敏与日志:这必须人工确认,因为它的失败方式是静默泄漏,工具不会报错。第二,权限相关的边界:令牌长度变了,但权限和仓库范围没变,所以任何"因为令牌变了所以权限也变了"的推测都不成立,别顺手扩大权限。第三,清理覆盖头:删除 X-GitHub-Stateless-S2S-Token 是一次有明确截止日期的代码变更,需要排进迭代,不能靠"反正还能用"拖着。

怎么核对

先在代码库里搜三样东西:字符串 ghs_ 出现的所有位置;字面量 40 与令牌处理代码相邻的地方;正则里带 40 或类似定长量词的表达式。这三点基本能覆盖长度假设的绝大部分藏身处。

再核对基础设施:数据库里与令牌相关的列宽、secret store 与 CI 环境变量的单值长度上限、以及链路上所有会处理 Authorization 头的代理、网关和 WAF,确认它们不会截断长头。

最后核对日志与脱敏:拿一个真实的 520 字符令牌样本,走一遍日志链路,确认输出里不留完整令牌。确认兼容后,删除生产代码里的 X-GitHub-Stateless-S2S-Token 头,并把它从测试脚本里一并清掉——2026 年 11 月 30 日之后它不再起作用,留着只会让人误以为还有退路。

信息来源

本文事实来自上述 GitHub 官方 changelog;配图为按官方公布内容编辑绘制,未添加公告之外的信息。


HiFox:将 Agent 变成真正的队友

另外,我们也在思考,AI 如何从个人提效走进团队协作。

HiFox 是一个让人和 AI Agent 在同一个工作现场协作的平台:你可以像给同事分派任务一样指派 Agent,在任务看板中跟踪进度、查看结果,让 Agent 成为团队里的队友。

👉 立即体验 HiFox:https://hifox.com

AI Coding 交流群

如果你也在用 AI 写代码,或者正在研究 Cursor、Claude Code 这些工具,
欢迎加入以下交流群。群里平时会聊一些 AI 编程的实际用法、开发工作流,还有各种新工具和新玩法。

AI Coding 交流群