Missing access checks on caller-supplied video/space IDs (4 endpoints, PRs open)
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 25/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 停滞
- 技術スタック
- next.js, typescript
- 領域
- api, authorization, security
調査の方向性
開始する前にPR #2029–#2032を確認し、その後VideosPolicy.canView、getSpaceAccess、/api/analytics/route.ts、Analytics.tsxを読んで既存のチェックを理解してください。4つの記載されたエントリポイントが適切なアクセスチェックを実施し、拒否時にnot-foundレスポンスを返し、オープンなPRですでに対応されている作業を重複させなければ完了です。
索引モデルが issue の本文から書いたものです。
説明
While working on #1982 I audited every entry point in apps/web that accepts a caller-supplied resource ID, since that advisory looked like an instance of a pattern rather than a one-off. It was — I found four, and opened a PR for each.
The pattern
Cap has a solid access-control primitive in VideosPolicy.canView, and most code uses it. The failures all have the same shape: a second entry point to the same data that skips the check. Server actions are the main way this happens, because a "use server" function is independently callable by any client and does not inherit whatever gating its usual API route does.
What I found
| PR | Entry point | State before | Impact |
|---|---|---|---|
| #2029 | newComment action |
authenticated only | write comments/reactions into anyone's private video, notifying the owner |
| #2030 | getVideoAnalytics action |
no auth at all | read view counts of any private video |
| #2031 | getSpaceVideoIds / getFolderVideoIds |
authenticated only | enumerate video IDs in spaces of orgs you aren't in |
| #2032 | /api/video/transcribe/status |
authenticated only | read transcription status of anyone's private video |
Two are worth calling out specifically:
#2030 is the sharpest. /api/analytics/route.ts does gate on canView, with a comment stating it exists so private view counts aren't disclosed. But getVideoAnalytics is a server action with zero auth of any kind — no getCurrentUser, no policy — and a "use client" component (Analytics.tsx) already calls it directly. The route's protection is bypassable by calling the action the same way the app's own client code does.
#2031 leaks IDs, which are the key to everything else. Video IDs are what /s/{videoId} and the other video endpoints take, so enumerating a private space's ID set is useful to an attacker even before any per-video check runs.
Sweep result
After these four, I re-swept: no remaining videoId-taking server action or API route in apps/web lacks an access check. Two files still show up in a naive grep but are fine on inspection — /api/notifications takes no ID and only returns the caller's own rows, and /api/tools/loom-download takes a Loom video ID, not a Cap resource.
Notes on the fixes
- Every fix reuses an existing primitive (
VideosPolicy.canView, orgetSpaceAccessfor the space paths) rather than introducing new logic, so they inherit the full existing model — owner, org, space, public, password, email-domain restrictions. - For #2031 I used
getSpaceAccessand notrequireSpaceManager: these are read paths, and requiring manager would have locked out ordinary members. - Denials return "not found" rather than "denied" throughout, so none of them become an oracle for which IDs exist.
- Each PR is 1–2 files. They're independent and can be merged in any order.
Happy to consolidate them into a single PR if you'd prefer to review it that way.
cc @richiemcilroy
- 主要言語
- Rust
- スター
- 22.5k
- フォーク
- 1.9k
- 平均マージ
- 6時間 33分
- マージ済み PR(30日)
- 77
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
CapSoftware/Cap のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
CapSoftware/Cap#2305 · コメント 2 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
CapSoftware/Cap#1714 · コメント 3 件 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 58/100
CapSoftware/Cap#2329 · コメント 2 件 ·
-
難易度 5/5 1週間以上 初心者へのやさしさ 35/100
CapSoftware/Cap#2328 · コメント 1 件 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 67/100
CapSoftware/Cap#2324 · コメント 1 件 ·
CapSoftware/Cap の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
-
state:needs triage
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
zed-industries/zed#64680 · コメント 2 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
RustPython/RustPython#8802 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
TheLarkInn/aipm#2390 ·