2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Brotli の脆弱性、Fiber ではボディの読み方で影響が分かれた話(2026年版)

2
Posted at

はじめに

GMOコネクトの永田です。

Brotli のデコーダの脆弱性(CVE-2026-111497)が公開された翌週、私が開発している案件で、Go で書いた API サーバーが影響を受けるかを調べることになりました。依存関係を見ると、修正前の Go 版の Brotli(github.com/andybalholm/brotli v1.2.0)が、Fiber と fasthttp 経由で入っていました。アプリのコードは Brotli を一度も呼んでいません。

調べると、Fiber はハンドラがボディを読むときに自動で展開するので、呼んでいなくても外から脆弱な処理に届きました。一方で、同じ Fiber でも fasthttp の版によっては、別の Brotli のライブラリが入っていて、そちらはメンテナが影響を受けないと回答しています。依存関係に入っているかだけでは、どちらとも言えませんでした😇

最小の Fiber アプリで、影響を受けるかを分ける条件を順に確かめた記録です。

先にまとめ

章 確かめること 分かれ方
2 どの Brotli のライブラリが入っているか fasthttp v1.73.0 以前は andybalholm/brotli(v1.2.7 未満は修正前)。v1.74.0 以降は go-brrr に替わっていて、メンテナは影響なしと回答
3 ハンドラがボディをどう読むか c.Body() と BodyParser(JSON・XML)は展開する。BodyRaw()・FormValue()・multipart は展開しない
4 recover ミドルウェアがあるか 無ければ、panic 1回でプロセスごと止まる。あれば、そのリクエストが500になるだけ
5 govulncheck で見つかるか 見つからない。Go の脆弱性DB・OSV・GitHub Advisory のどれにも、andybalholm/brotli の登録が無い
  • Content-Type はリクエストを送る側が決めます。フォームで受けているつもりの API でも、BodyParser を使っていれば、JSON を指定されて展開が動きます
  • Fiber v3.6.1 は fasthttp v1.75.0 を要求するので、go-brrr が入ります。Fiber v2 は、アプリ側の fasthttp の版しだいです
  • govulncheck の「影響を受ける脆弱性は0件」は、この件では「影響なし」を意味しません。バイナリに入っている版は go version -m で見られます

1. 何をどう確かめたか

項目 条件
確かめた日 2026年10月30日
Go go1.27.3(darwin/arm64)
構成A Fiber v2.52.16、fasthttp v1.68.0、andybalholm/brotli v1.2.0
構成B Fiber v3.6.1、fasthttp v1.75.0、molecule-man/go-brrr v1.3.0
送ったボディ 正常な Brotli で圧縮した JSON・XML・フォーム・multipart。Content-Encoding: br を付けた。攻撃データは使っていない
govulncheck v1.9.0(脆弱性DBの更新日時は 2026-10-27)

アプリ側は Brotli も、Fiber の compress ミドルウェアも使いません。ハンドラは、読み方を変えたものを並べただけです。

app := fiber.New()
app.Post("/body", func(c *fiber.Ctx) error { return c.Send(c.Body()) })
app.Post("/bodyraw", func(c *fiber.Ctx) error { return c.Send(c.BodyRaw()) })
app.Post("/bodyparser", func(c *fiber.Ctx) error {
	var r struct {
		Name string `json:"name" xml:"name" form:"name"`
	}
	if err := c.BodyParser(&r); err != nil {
		return c.SendString("error: " + err.Error())
	}
	return c.SendString(r.Name)
})
app.Post("/formvalue", func(c *fiber.Ctx) error { return c.SendString(c.FormValue("name")) })

展開されたかは、ハンドラが返したバイト列が送ったバイト列と同じかで判定しました。最初は中身の文字列が含まれるかで判定していて、BodyRaw() を「展開された」と誤判定しました。短い入力だと、Brotli は圧縮せずにそのまま格納するためです。

2. Brotli のライブラリは、fasthttp の版で替わる

fasthttp は v1.74.0(2026年9月)で、Brotli のライブラリを替えています。リリースノートの1行です。

Replace github.com/andybalholm/brotli with github.com/molecule-man/go-brrr

ビルドしたバイナリに何が入っているかは、go version -m で見られます。

# 構成A
dep  github.com/andybalholm/brotli  v1.2.0
dep  github.com/valyala/fasthttp    v1.68.0
# 構成B
dep  github.com/molecule-man/go-brrr  v1.3.0
dep  github.com/valyala/fasthttp      v1.75.0

go-brrr がこの CVE の影響を受けるかは、issue で聞かれたメンテナが答えています。

go-brrr is a pure Go port. It does not link or call libbrotli.

In the c code the decoder ignored a failed block switch when a stream has only one block typ.(原文ママ) go-brrr decoder never calls the block switch in that case: each call site checks for more than one block type first.

この回答は、手元では攻撃データで確かめていません。

Fiber v3.6.1 は fasthttp v1.75.0 以上を要求するので、更新していれば go-brrr になります。Fiber v2.52.16 が要求するのは fasthttp v1.51.0 以上で、実際に入る版はアプリの go.mod で決まります。構成A(Fiber v2)のまま fasthttp を v1.77.0 に上げると go-brrr に替わり、展開もそれまでどおり動きました。ただし fasthttp v1.77.0 は Go 1.26 以上が要ります。fasthttp を上げられないなら、go get github.com/andybalholm/brotli@v1.2.7 で修正版に上げる手もあります。

3. 展開が動くかは、ボディの読み方で決まる

構成A・構成Bとも、結果は同じでした(v3 では BodyParser の代わりに Bind().Body())。

ハンドラの読み方 Content-Type 結果
c.Body() JSON 展開された
BodyParser JSON 展開された
BodyParser XML 展開された
BodyParser フォーム 展開されない
BodyParser multipart エラー(unsupported Content-Encoding: "br")
c.BodyRaw() JSON 送ったバイト列のまま
c.FormValue() フォーム 展開されない
c.MultipartForm() multipart エラー(unsupported Content-Encoding: "br")

Fiber の文書にも、Body() はヘッダを見て展開すると書かれています。

As per the header Content-Encoding, this method will try to perform a file decompression from the body bytes.

BodyParser は Content-Type が JSON か XML のとき、内部で c.Body() を呼びます。そのため、アプリが Brotli を一度も呼んでいなくても、展開の処理が動きます。

Content-Type は送る側が決めます。正規のクライアントがフォームで送ってくる API でも、ハンドラが BodyParser を使っていれば、攻撃する側は JSON を指定して c.Body() の経路に乗せられます。Content-Encoding: br を付けたリクエストはどの API にも送れますが、試した読み方の中で展開が動いたのは、ボディを c.Body() か BodyParser(JSON・XML)で読んだときだけでした。

4. 展開で panic したとき、recover が無いとプロセスごと止まる

Sweet Security の記事によると、andybalholm/brotli に細工したデータを渡すと、範囲外の書き込みにはならず、境界チェックで panic(index out of range [8] with length 8)になります。そのうえで、次のように書いています。

Depending on how the application handles panics, exploitation could disrupt requests or terminate the affected process.

どちらになるかは、panic をどこで回収するかで決まります。Fiber の文書には次の1文があります。

Fiber does not handle panics by default.

展開は c.Body() の中、つまりハンドラの中で動きます。攻撃データは使わず、ハンドラの中でわざと panic させて代わりにしました(各1回)。

構成 recover ミドルウェア panic したリクエスト プロセス 後のリクエスト
A(v2) なし 応答なし 終了した 応答なし
A(v2) あり 500 動いている 200
B(v3) なし 応答なし 終了した 応答なし
B(v3) あり 500 動いている 200

recover が無いと、1回のリクエストでサーバー全体が止まります。Go の標準の net/http は、ハンドラの panic を回収して、そのリクエストだけを打ち切ります(go doc net/http.Handler の "If ServeHTTP panics, the server ... recovers the panic")。Fiber(fasthttp)は、ここが net/http と違います。

5. govulncheck では見つからない

構成A のバイナリには andybalholm/brotli v1.2.0 が入っていますが、govulncheck の結果は次のとおりでした。

Your code is affected by 0 vulnerabilities.
This scan also found 1 vulnerability in packages you import and 2
vulnerabilities in modules you require, but your code doesn't appear to call
these vulnerabilities.

呼んでいない脆弱性として fasthttp や klauspost/compress のものは出ましたが、brotli は1件もありません。Go の脆弱性DB、OSV、GitHub Advisory のどれにも、andybalholm/brotli のエントリがありませんでした。CVE のレコードも、影響を受ける製品に載っているのは Google の C 実装(1.0.3〜1.2.0)だけです。

登録されるまでは、govulncheck には頼れません。go version -m <バイナリ> か go list -m all で brotli の版を見ておく必要があります。

まとめ

Go のサーバーがこの CVE の影響を受けるかは、修正前の andybalholm/brotli が依存関係にあるかだけでは決まりませんでした。fasthttp が v1.74.0 以降なら、別のライブラリに替わっています。修正前のライブラリが入っていても、ハンドラが c.Body() か BodyParser(JSON・XML)でボディを読まなければ、展開は動きません。逆に、フォームで受けているつもりの API でも、BodyParser を使っていれば JSON を指定されて展開が動きます。Fiber は net/http と違って panic を回収しないので、recover が無ければ1回のリクエストでプロセスが止まります。そして確かめた時点では、govulncheck はこの件を何も報告しませんでした。


最後に、GMOコネクトではサービス開発支援や技術支援をはじめ、幅広い支援を行っておりますので、何かありましたらお気軽にお問合せください。

お問合せ:https://gmo-connect.jp/contactus/

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?