本日3/6に、 Go 1.26.1 と Go 1.25.8 がリリースされました。
本バージョンで修正された脆弱性のひとつは私が見つけたものです。
せっかくの人生初のCVEなので、経緯を紹介しようと思います。
脆弱性の内容
脆弱性は以下で公開されています。
内容はシンプルで、url.Parse の構文解析のミスです。 https://example.com[::1]/ のような形の不正なURLを誤って通してしまい、 https://[::1]/ のような IPv6 URL として取り扱ってしまいます。
バグを発見するまで
このバグは、PostgreSQLのURLのパーサーを自作しようとしていて発見しました。
PostgreSQLのURLは実際にはURLの仕様に準拠しないか、準拠性が不明確な特殊仕様があります。
- ホスト部分に %2F を含むことができる。たとえば
postgres://%2Fvar%2Frun%2Fpostgresql/database と書いた場合、このURLは /var/run/postgresql/.s.PGSQL.5432 上に存在する Unix domain socket への接続を指示します。 - ホスト部分に複数の host/port pair を含むことができる。たとえば
postgres://host1.local,host2.local/database と書いた場合、このURLは指定されたホストへの接続を順に試します。
これらはクエリパラメーターにも含められるので、非標準なURL形式を使えなくても実用上の問題はないのですが、libpqの挙動を模倣しようと思うとこうした形式への対応を考える必要が出てきます。
URLパーサーを自作するにあたって、標準ライブラリ実装である url.Parse を参考にしながら挙動を拡張することを考えました。その過程で url.Parse 内にあるホスト名のパース処理を追っていたところ、怪しいコード断片を見つけました。
func parseHost(scheme, host string) (string, error) {
if openBracketIdx := strings.LastIndex(host, "["); openBracketIdx != -1 {
このコードはIPv6用のブラケットを検出しています。ここで検出条件として「ホスト中に開き角括弧が存在する」という条件を使っています。しかしIPv6 hostnameでは角括弧は先頭になければいけません。その齟齬が怪しいと感じました。
脆弱性を報告するまで
まず再現条件を確認
今回の脆弱性はプラットフォーム依存性はほぼないため、最新バージョンで再現するかどうかを確認します。
これには Go playground を使用します。これにより以下が確認できます。
- 最新安定版 (1.25.5, 当時) で再現すること
- 開発ブランチの先端で再現すること
脆弱性かどうかを考える
このバグが脆弱性とみなせるかどうかによって、報告の方法が大きく異なってきます。
- 多くのプロジェクトで、通常のバグは公開の場で報告されます。これは、他のユーザーとの情報共有を促進し、重複された報告をなるべく抑止し、またユーザーのプロジェクトへの参加を促すことができます。
- いっぽう、悪用可能なセキュリティ脆弱性を公開の場で議論すると、そのまま悪意あるアクターに発見され悪用されてしまいます。そのため、信頼できる関係者だけがいる場でトリアージし、対応する必要があります。
そのため、まずはこのバグが脆弱性とみなせるかどうかを考える必要があります。
私はセキュリティまわりの知識、特にバグの悪用方法について熟知しているわけではないため、ここでChatGPTに相談してみます。結果としては類似のケース (URLのパーサーバグ) で脆弱性扱いとしてCVEが発行されている事例はいくつかあり、 Go の過去事例もありました。そこで、ここからはこのバグを脆弱性として扱うことにしました。
メールを送信
ここから先は、プロジェクトの方針にしたがって脆弱性を報告していきます。
Go Security Policy によると、まずはメールで脆弱性を報告してほしいとあります。そこで ChatGPT と相談しながらメールをしたためます。このときメールに "vulnerability" という単語を入れるよう指示があったため、それも含めておきます。
Subject: Possible vulnerability: net/url.Parse accepts invalid host like example.com[::1]
Date: Thu, 15 Jan 2026
Hello Go Security Team,
I believe net/url.Parse in the Go standard library insufficiently
validates the host/authority component and accepts some invalid URLs
by effectively treating garbage before an IP-literal as ignorable.
Example input:
https://example.com[::1]/foo
Observed behavior (Go 1.25.5):
Parsed result corresponds to:
https://[::1]/foo
(i.e., the "example.com" portion is not preserved/causes no error, and
round-tripping via u.String() yields a different URL).
Expected behavior:
Parsing should reject this as invalid.
Why this may be security-relevant:
Applications commonly use net/url.Parse to validate user-supplied URLs
(SSRF defenses, redirect allowlists, etc.). Accepting invalid URLs and
normalizing them into a different authority can enable
parser-differential or allowlist-bypass scenarios when different
components interpret the input differently, or when logging/validation
uses the original string while requests use the parsed form.
Reproduction:
Go version confirmed: Go 1.25.5
Snippet: https://go.dev/play/p/FMtPNgxF2JZ
About me:
https://github.com/qnighy
I’m reporting this privately as a potential vulnerability, given prior
URL parser issues (e.g., CVE-2024-11168, CVE-2025-47912). If you
consider this non-security, I’m happy to file it as a normal public
issue instead.
Thanks,
Masaki Hara
メールを再送
7日経っても返事がなかったため、 Go Security Policy の記述にしたがってメールを再送します (1月22日) 。
Hello,
Last week I sent a vulnerability report. Did you receive it?
Note that it also reproduces in go1.27-devel_2d37c20 2026-01-21
16:01:08 -0800 darwin/arm64.
Masaki
ChatGPTに書いてもらった丁寧な文面があだになったかと考え、今回は自分でシンプルな英語で書きました。その結果、翌日に返事が来ました (1月23日) 。やはり1通目はスパムボックスに入っていたようです。
CVEがアサインされた
その後、 CVE-2025-***** がアサインされ、 PRIVATE トラックで管理することが伝えられました。 (1月30日)
なお、2026年に報告したにもかかわらず、なぜか2025年の番号がアサインされたのかはよくわからず、謎に思っていました。
Go では、脆弱性の深刻度は利用側の状況に依存するという考え方から、細粒度の深刻度モデルを採用していません。かわりに脆弱性は以下の3種類のトラックに分類されます。
- PUBLIC は、ごく限られた条件で問題になる脆弱性のトラックです。公開のチャンネルで対応されます。
- PRIVATE は、Goが約束しているセキュリティ上の堅牢性に対する違反にあたる脆弱性のトラックです。非公開のチャンネルで対応され、修正はパッチバージョンに含まれる形でリリースされます。
- URGENT は、Goのエコシステムに深刻な打撃を与える脆弱性や、すでにゼロデイ攻撃により深刻な被害が出ている脆弱性のためのトラックです。リリーススケジュールを無視して即座に修正がリリースされます。
PRIVATE に分類されたということは、本脆弱性は明確に問題のある状態だと認められたということになります。
どのようにクレジットしてほしいか聞かれたため、以下のように返答しました。
Could you credit me as Masaki Hara (https://github.com/qnighy) of Wantedly?
Go 1.26.0 がリリースされた → 対応されていなかった
脆弱性を報告して少し後に、ちょうど Go 1.26.0 がリリースされました (2月10日)。Goは半年おきにマイナーリリースが出ますが、それが2月と8月に位置しています。
また、 go1.25.7 もリリースされました (2月4日)。Goのパッチリリースはおおむね1ヶ月おきに出るためです。
このタイミングでは当該脆弱性の修正は含まれませんでした。
Goのセキュリティーポリシーでは、脆弱性が認識されてから90日以内に修正または公表されるとされています。本脆弱性の場合は最大4月30日くらいまでは待つ必要があることになります。
Go 1.26.1 がリリースされ、対応された
その1ヶ月後、 3月5日に Go 1.26.1 と 1.25.8 がリリースされ、このパッチリリースで当該脆弱性が修正されました。
修正PRにも、希望通りに名前をクレジットしてもらいました。
なお、事前にメールでいただいていたCVEとは異なる番号 (CVE-2026-25679) がアサインされていました。最初の番号はなぜか2025だったのもあり、何かしらの割り当てミスだったのかもしれません。
おまけ
本脆弱性ですが、昔から存在したものではなく、先行する CVE-2025-47912 の修正時にエンバグしたものだと考えられます。
もしかしたら、私が見つけていなくても近いうちに誰かが見つけていたのかもしれません。
まとめ
- Goの脆弱性を見つけたので、 Security Policy を参考に報告してみた
- 今回は報告してから2ヶ月弱で修正された
- ちゃんとしたコードでも、じっくり読んでみると偶然脆弱性に出会うこともある。皆さんも有名OSSをじっくり読んでみることをおすすめします。