本篇话题 gogs/gogs SSRF CVE-2022-1285 GHSA-w689-557m-2cvq
一句话 你写个地址,它就照着去跑一趟。官方公告说这个毛病修好了,其实没修好。
原始报告 github.com/gogs/gogs/issues/7031(至今 open)
各位老哥,今天这个瓜我得说一句:这个比我想的还拧巴。
好家伙,我原本以为是「修了一半就宣布全好了」,结果比那还绕。
一个人三年前对外宣布「这个洞修好了」,还贴了一张公开公告。
七天后,有人升级完上手一测,回了一句:
are claimed to be fixed. But still exist via test.
(声称已修复。我测下来它还在。)
然后他做了一件事:把这个人的报告关掉了。
59 秒后,他自己又打开了。
再过 34 分钟,他说了一句话。那句话等于承认:当年那个补丁,修的根本不是根因。
先把那个洞讲明白
不提那些术语。就一句话:
有人在群里喊一句「谁有空帮我取个快递,单号是 XXX」,发单号的人可以随便写。
他写你家的门牌号,你就真去了。
gogs 里那个叫 webhook 的功能就是这个角色:外部系统发个消息过来,gogs 自动按消息里给的地址去跑一趟。
发地址的人不受限制。 那他就可以填一个只有服务器自己能到达的地址 ------ 比如它自己的内网。
洞就在这儿。服务器变成了别人的跑腿。
现场
项目 gogs/gogs,47879 星(2026-10-17 亲测)。一个自己搭的「小型代码服务器」,不少小团队拿它托管内部仓库。
谁 维护者 @unknwon (真名 Oleg Zaytsev),从项目早期就在,一个人管着。 报告者 @cokeBeer,普通用户。
修了什么 CVE-2022-1285,安全公告号 GHSA-w689-557m-2cvq。
结果 宣布修好,7 天后有人说还在。
全部是 GitHub 公开页面,不用登录。
一、宣布修好
2022 年 4 月 9 日,有人把那个洞报上去,开了 #6901,标题就叫「SSRF in webhook」。
5 月 31 日 07:17:18,维护者自己关闭了它。
当天上午 09:31:41,v0.12.8 发布。
两小时后,11:37:34,他在那个 issue 里留了一句话,逐字:
The 0.12.8 has been released that includes the patch of the reported issue. The security Advisory has been published at ...GHSA-w689-557m-2cvq.
(0.12.8 已发布,包含了对该问题的补丁。安全公告也已发布。)
那张公告上写得清清楚楚:
Affected versions <0.12.8 Patched versions 0.12.8
三处都写着。更新日志里那条是:- _Security:_ SSRF in webhook. [#6901]
从公告到版本号到更新日志,三个地方都写着「修好了」。
二、7 天后
一周后,v0.12.9 发布:6 月 7 日 15:35:01。
第二天早上 05:39:36 ,@cokeBeer 开了新 issue,标题是「Unresolved SSRF in webhook」。
in changelog of 0.12.9, ...#6901 are claimed to be fixed. But still exist via test.
距离新版发布,14 小时 4 分 35 秒。
一个细节,但别当噪音看
他写的版本号是 0.12.9,更新日志里那条挂在 0.12.8 底下。
他跑的确实是 0.12.9,只是翻的是上一版的日志。
这条差一个版本号不影响结论 ------ 不管他写哪个版本号,他升级之后测出来那个洞,都还在。
但它顺带说明了一件事:连来报这个洞的人,都没能第一时间翻到那条记录。
三、59 秒
6 月 9 日,@cokeBeer 那个 issue 挂了几天。
10:54:18,维护者把它关掉了。
10:55:17 ------ 他自己重新打开。
中间隔了 59 秒。
各位老哥,划一下这 59 秒。
关掉别人的报告,35 分钟之后又自己开回去,还顺手说明了真正该怎么修。
这三个动作连在一起,等于同一句话说了三遍:这事我搞错了,但我没打算装作没事。
他一个字理由都没留。 关闭事件不带评论正文。
四、那一行字
重新打开之后 33 分 53 秒 ,也就是 11:29:10,他留了一行:
Note: disable follow redirects in HTTP client.
(注:在 HTTP 客户端里,别跟着跳转走。)
老哥们,这一行是全文最狠的地方。
它不是辩解,是施工图。
他用一行字说清了「当年该怎么修」。也就等于承认:当年那个补丁,没这么做。
而 0.12.8 那次修的是什么?同一份日志的另一个版本段里写着:
All users (including admins) need to use the configuration option
[security] LOCAL_NETWORK_ALLOWLISTto allow repository migration and webhooks to be able to access local network addresses...
(所有用户需要配置 [security] LOCAL_NETWORK_ALLOWLIST 来放行本地网络地址......)
他做的是「加个开关,让你手动列出哪些内网地址可以访问」。
他该做的是「不跟着跳转走」。
一个治标,一个治本。他选了治标,然后宣布治好了。
📌 四年后,这条又原样回来了一次。2026 年 6 月发布的 v0.14.3, 那条修复的标题逐字是:Server-side request forgery in webhook deliveries via HTTP redirects to local network addresses 。 「via HTTP redirects」------ 正是他 2022 年 6 月说的那个词。
五、685 天
2023 年 12 月,一位赏金研究者 @Sim4n6 找到了当年的报告链接:
Indeed, this is what lead to this security report ...
然后 2024 年 4 月 10 日:
Hi, any update on this please?
下午 13:05:52,维护者回了:
Hi @Sim4n6, based on the linked report, the current status is "Awaiting fix" . If you feel about it, PRs welcome :D
(当前状态是「等待修复」。你要有兴趣的话,欢迎提 PR :D)
从宣布修好那天算,到他说这句「等待修复」,680 天。
他用四个字,把三年前那句「已修复」收了回去。
同一天下午 15:23:44,又有人问:
Do you have any bug bounty reward program for identifying vulnerabilities and suggesting fixes please?
他回:
Unfortunately, we do not have bug bounty reward program.
(抱歉,我们没有漏洞赏金计划。)
找赏金的没有赏金,提 PR 的等了一年。
那个 issue 到今天(2026-10-17)仍然是 open,最后一条活动停在 2024 年 4 月 10 日。
六、拉个表
时刻 / 发生了什么
- 2022-04-09 05:59:01 ------ 洞被报上去,开了 #6901
- 2022-05-31 07:17:18 ------ 维护者关闭 #6901
- 2022-05-31 09:31:41 ------ v0.12.8 发布
- 2022-05-31 11:37:34 ------ 宣布「包含了对该问题的补丁」
- 2022-06-07 15:35:01 ------ v0.12.9 发布
- 2022-06-08 05:39:36 ------ 「声称已修复。我测下来还在。」
- 2022-06-09 10:54:18 ------ 维护者关闭这个报告
- 2022-06-09 10:55:17 ------ 他自己重新打开 ------ 相隔 59 秒
- 2022-06-09 11:29:10 ------ 「别跟着跳转走。」
- 2024-04-10 13:05:52 ------ 状态改口:「等待修复」
- 2024-04-10 15:23:44 ------ 「我们没有漏洞赏金计划」
- 2026-06-07 20:51:06 ------ v0.14.3 ------ 同类问题又单独立项修了一次
- 2026-10-17(今天) ------ #7031 仍 open,已 1599 天
四个数字:
- 59 秒 ------ 关掉到打开
- 7 天 18 小时 ------ 宣布修好到有人说还在
- 680 天 ------ 宣布修好到官方改口说「等待修复」
- 1599 天 ------ 宣布修好到今天
七、这事最扎心的一句
写完这个 case,我卡在最后这一句上:
没有人在滥用任何东西。没有人拦错任何一份补丁。没有说错任何一个字。
偏偏就是这三句「没有」,把整件事定了性。
他只是把自己三年前写下的那个「修好了」,又读了 59 秒,然后关掉了别人的报告。
前面几篇我写过:一道门跑偏了,一条判据被废了,一个门被堵死了,三种死法,一个门忘了自己该重新评估。
这一篇是另一种,也是最安静的一种:
判据跑了,也跑对了。它没跑偏,也没撒谎。它只是 修的是症状,然后对着症状宣布「好了」------顶多算对症下药,没对病根。
而真正的解法,是他自己在 34 分钟后写下的那一行。
三年后,同一行字又出现在了更新日志里,这次后面跟着一个工单号。
本篇不成立的结论
以下几条不能从本文推出去:
- 先说清楚:这不等于「gogs 这个项目不行」。 47879 星的项目,修过别的洞,
四年后自己也把这个洞认真修了。本文盯的是一件事:一个补丁修得不对。
- 也别读成「维护者不负责任」。 他关了又自己开回来,写出了真正该怎么修,
还公开把状态改成「等待修复」、公开说欢迎提 PR。 本文没有一句指控他在偷懒或者想隐瞒 ------ 恰恰相反。
- 推不出「那 59 秒里发生了什么」。 他一个字都没留。
关闭事件不带评论正文,我没有替它编动机。
- 更写不得「0.12.9 声称修了」。 更新日志里那条在 0.12.8 底下。
报告人自己写的是 0.12.9,保留他的原话,不改写。 但结论不受影响 ------ 他升级之后测,那个洞还在。
- 同样推不出「v0.14.3 那次顺带解决了 #7031」。 未核。
#7031 从未被关闭,官方也从未把它标为已修。
- 别把这篇读成「安全公告不可信」。 公告上「Affected <0.12.8 /
Patched 0.12.8」写得没错 ------ 按那个定义,0.12.8 确实不再受影响了。 错的是「修好了」这三个字,而不是公告里的版本区间。
附:本文引用
都是公开地址,不用登录。
- 那个说「我测下来还在」的 →
github.com/gogs/gogs/issues/7031 - 宣布修好的那个 →
github.com/gogs/gogs/issues/6901 - 安全公告 →
github.com/gogs/gogs/security/advisories/GHSA-w689-557m-2cvq - 更新日志(0.12.8 与 0.14.3 两条)→
github.com/gogs/gogs/blob/main/CHANGELOG.md
- 四年后那次修复 →
github.com/gogs/gogs/pull/8263 - 三年后那位赏金研究者贴的报告 →
huntr.com/bounties/f57e0882-8a85-4120-97a3-de7bdb8965a4
- 仓库规模 →
github.com/gogs/gogs
时间戳全部取自 GitHub 页面与 tag 页的原始记录,精确到秒,都是 UTC。 所有引语逐字未改。所有天数都是本机算的。