
Bitwarden Server v2026.9.2 - 高 - IDOR - 呼び出し元が書き込みできないコレクションに復号可能な保管庫アイテムを植え付ける
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · bitwarden-cipher-create-acl
解説記事: https://abraxaslabs.tech/research/bitwarden-cipher-create-acl
Bitwarden Server v2026.9.2 - Bitwarden
Entity Framework 経路(MariaDB、Postgres、SQLite)における組織 cipher の作成では、コレクションへのアタッチ前に呼び出し元の id が失われます。確認済みのメンバーは、自身が書き込み権限を持たないコレクションに組織キーのアイテムを植え付けることができます。コレクションメンバーはそれを通常の共有ログインとして同期します。
| ID | CVE 未割当 |
| CWE | CWE-863 / CWE-639 |
| CVSS | High: 7.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L |
| 製品 | Bitwarden Server |
| 影響範囲 | v2026.9.2 (9ee4e0eb) lite EF(MariaDB / Postgres / SQLite)。MSSQL/Dapper は @UserId を保持します。 |
| 認証 | 確認済みの組織メンバー |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1 のみ |
攻撃者は共有コレクションに保管庫アイテムを追加します。既に存在するシークレットを読み取ったり置き換えたりすることはできません。
確認済みの組織メンバーは既に組織キーを所持しているため、新しいアイテムはそのコレクションを閲覧できる全員に対して復号されます。Bitwarden 上では、社内保管庫内の通常の共有ログイン、ノート、カード、または SSH キーとして表示されます。
Okta、GitHub、VPN、Payroll)に似た名前のログインを植え付け、その URI を攻撃者が管理するホストに向けます。コレクションメンバーが Bitwarden から開くと攻撃者のページに到達するか、類似サイトに対して自動入力が行われます。new AWS key、bastion SSH key、DB password after change)を植え付けます。誰かがそれを本番環境やターミナルにコピーしてしまいます。Production を読み取り専用でしか閲覧できない請負業者でも、lite EF 上では新しいアイテムをそこに投入できます。対象コレクションへのアクセス権がない場合、POST /api/ciphers/create は書き込みが既にコミットされた後に 404 を返すことがあります。それでも被害者は同期時にアイテムを受け取ります。
2026 年の一連の波(管理者リクエスト TDE(CVE-2026-60104)、SSO ExternalId の切り捨て(CVE-2026-101878)、組織インポートの空コレクション(CVE-2026-43638))の後、bitwarden/server v2026.9.2 (9ee4e0eb) を固定しました。これらは修正済みです。作成時のコレクション ACL は修正されていませんでした。
CiphersController.PostCreate は組織メンバーシップのみを確認し、OrganizationId が設定されている場合は skipPermissionCheck: true を渡します。続いて SaveDetailsAsync は「このコレクションが組織内に存在する」ことだけをコレクションのチェックとして扱います。
lite MariaDB/Postgres/SQLite は EF を使用します。CreateAsyncReturnCipher は組織 id が存在するため cipher.UserId = null を設定し、その null を UpdateCollectionsAsync に渡します。ユーザー id が null であることは、組織内のすべてのコレクションを意味します。SQL Server Dapper は Cipher_UpdateCollections(ReadOnly = 0)に対して @UserId を保持します。この経路がネガティブケースです。
記録済みの誤った手順:クラウドの POST /organizations をセルフホストの作成とみなすこと(これは [NotSelfHostedOnly] であり、lite はライセンスファイルを要求するため、ラボでは登録後に org 行をシードする);呼び出し元が読めないコレクションに植え付け、HTTP 404 をミスと解釈すること(CollectionCipher 行はすでにコミット済み);MSSQL lite なら表示されるはずと仮定すること(Dapper は呼び出し元 ID を削除しない);BW_ENABLE_ADMIN をオフのままにしたため lite が User / OrganizationDomain をマイグレーションしないこと(このイメージでは admin が EF マイグレーターである);/identity/connect/token で Bitwarden-Client-Version を省略し、パスワードグラントが 400 になるのを見ること。リバースシェル。茶番。
cd lab
./run.sh
対象は http://127.0.0.1:18160 のみ。イメージ ghcr.io/bitwarden/lite:2026.9.2 と MariaDB。
SUCCESS BITWARDEN-CIPHER-CREATE-ACL create-http=404 collectioncipher=1 victim-sync-has-cipher=yes cipher=<id> negative-http=404 readonly-http=200 BITWARDEN-CIPHER-CREATE-ACL-WITNESS
CollectionCipher のコミット後、アクセス権のない plant は 404 を返します。被害者の GET /api/ciphers と /api/sync の両方に新しい id が含まれます。B に対する読み取り専用アクセスは 200 を返し、依然として plant が可能です。外部組織のコレクションは join 行なしで 404 のままです。
保存するユーザー id を、CipherDetails_CreateWithCollections が保存済みの UserId カラムを null にした後でも @UserId を渡し続けるのと同じ方法で、EF の UpdateCollectionsAsync に渡します。メンバー作成パスにおいて、null ユーザーを「すべてのコレクション」として扱わないでください。組織内に存在することは書き込みアクセス権ではありません。
CiphersController.cs (Post、PostCreate)CipherService.cs (SaveDetailsAsync)CipherRepository.cs (CreateAsyncReturnCipher、UpdateCollectionsAsync)