
CVE-2026-28699のラボとレポート: HTTP Basic認証を介したGitea OAuth2スコープ強制のバイパス
read:user のみにスコープされた Gitea OAuth2 アクセストークンが、Bearer トークンとしてではなく Authorization: Basic base64(<token>:x-oauth-basic) として送信されると、完全な書き込みアクションを実行できます。Basic 認証で提示されたトークンはスコープチェックがスキップされます。
影響を受けるバージョン: <= 1.26.1。修正バージョン: 1.26.2。
アドバイザリ: GHSA-9r5x-wg6m-x2rc。CWE-863。重要度: 高。
詳細な解説: WRITEUP.md
pip install -r requirements.txt # requests
python fetch_binaries.py # pulls vulnerable 1.26.1 + patched 1.26.2 for your OS
python poc.py 1.26.1 # vulnerable: Basic-auth write succeeds (scope bypassed)
python poc.py 1.26.2 # patched: Basic-auth write blocked (403)
poc.py はシステムの一時ディレクトリに使い捨ての Gitea を SQLite 上に立ち上げ、OAuth2 認可コードフローを実行して read:user のみのトークンを発行し、その後 Bearer と Basic の両方で書き込みエンドポイントを呼び出し、結果を表示します。POC_DEBUG=1 を設定すると認証フローの手順を表示できます。
脆弱な 1.26.1:
[Bearer] PATCH /api/v1/user/settings -> HTTP 403 (blocked)
[Basic ] PATCH /api/v1/user/settings -> HTTP 200 (ALLOWED -- scope BYPASSED)
>>> VULNERABLE: read:user token performed a write via Basic auth.
修正済み 1.26.2:
[Bearer] PATCH /api/v1/user/settings -> HTTP 403 (blocked)
[Basic ] PATCH /api/v1/user/settings -> HTTP 403 (blocked)
>>> PATCHED: scope enforced on both Bearer and Basic.
services/auth/basic.go は OAuth2 トークンに対して IsApiToken を設定するが ApiTokenScope は設定しない。スコープが欠落している場合、tokenRequiresScopes ミドルウェアは早期に戻るため、何もチェックされない。1.26.2 の修正では、欠落していた store.GetData()["ApiTokenScope"] = accessTokenScope が追加された。
教育および許可されたセキュリティテストのため: 自分のラボ、CTF や HTB のボックス、対象範囲内のバグバウンティのターゲット。PoC は自身の使い捨て Gitea を実行するため、所有していないものに向けてはいけません。
| 認証提示 | IsApiToken | ApiTokenScope | スコープ適用? |
|---|
| Bearer 経由の OAuth2 トークン | true | 設定あり | はい |
| Basic 経由の OAuth2 トークン | true | 欠落 | いいえ(フェイルオープン) |
| 個人アクセストークン | true | 設定あり | はい |
| ファイル | 目的 |
|---|
WRITEUP.md | 根本原因分析、影響、修正方法、検出 |
fetch_binaries.py | お使いの OS/アーキテクチャ用の 1.26.1/1.26.2 バイナリをダウンロードします |
poc.py | Gitea をプロビジョニングし、read:user トークンを発行し、Bearer と Basic をテストします |
requirements.txt | requests |