You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Unauthenticated Cross-User AI Metadata Disclosure via Missing Access Check on /api/video/ai #1981
The GET /api/video/ai endpoint retrieves AI-generated metadata (title, summary, chapters) for any video by ID without verifying whether the requesting user has permission to access that video. Any authenticated user can supply an arbitrary video ID and read the AI-generated content of another user's private recordings.
Details
The handler at apps/web/app/api/video/ai/route.ts (GET, lines 13-169) fetches the target video directly from the database using only the caller's authenticated session and the videoId query parameter:
const result = await db()
.select()
.from(videos)
.where(eq(videos.id, videoId));
No ownership check and no call to the VideosPolicy canView policy are made before returning the video's metadata fields. The response body includes:
metadata.aiTitle
metadata.summary
metadata.chapters
metadata.aiGenerationStatus
The correct access-guarded path used by every other video-reading endpoint is getByIdForViewing, which runs the full canView policy (owner check, org/space membership, public flag, password, email restriction). This endpoint bypasses all of that.
PoC
Preconditions: User A has a private video (public=false) with AI metadata populated. User B has no membership in User A's org or space and cannot view the video at /s/{videoId}.
Authenticate as User B and obtain a session token (cookie next-auth.session-token).
Note the video ID of User A's private recording (vid001vidtest00 in the test below). In practice an attacker would enumerate IDs or obtain one via a notification link or a shared URL they intercept.
Issue:
curl -s "http://<host>/api/video/ai?videoId=vid001vidtest00" \
-H "Cookie: next-auth.session-token=<User B token>"
Response (200 OK):
{
"processing": false,
"title": "Secret Report Title",
"summary": "This is a confidential summary",
"chapters": [],
"aiGenerationStatus": "COMPLETE"
}
User B receives the AI-generated title and summary of a video they cannot open. The /s/vid001vidtest00 share page correctly shows "This video is private" to User B, confirming there is no legitimate access path.
The same endpoint will also attempt to enqueue AI generation on behalf of the requester when aiGenerationStatus is SKIPPED and transcriptionStatus is COMPLETE, consuming the video owner's AI credits without their knowledge.
Impact
Any authenticated user can read the AI-generated title, summary, and chapter list of any other user's private video recordings. These fields are derived from the audio transcript and can contain sensitive, confidential, or personally identifying information. The bug affects all self-hosted Cap deployments running the current codebase.
This vulnerability was fixed in PR #1926, merged on June 19, 2026. The /api/video/ai endpoint now gates access through Policy.withPublicPolicy(videosPolicy.canView(videoId)) before returning any metadata - you can see the check at apps/web/app/api/video/ai/route.ts:38.
The same PR also added canView checks to the transcript, translate-transcript, and available-translations endpoints, plus rate limiting on the translation endpoint.
For self-hosted deployments: pulling the latest main branch or any release after June 19, 2026 will include this fix.
Related security work still in progress:
PR #1928 - ownership checks on folder/space/org video actions
Fixed by #1926 (merged June 19, 2026). The /api/video/ai endpoint now gates access through Policy.withPublicPolicy(videosPolicy.canView(videoId)) before returning any AI metadata, so cross-user reads of private video metadata are rejected. Closing.
Activity
linear commentedon Jul 6, 2026
CAP-748
tembo commentedon Jul 6, 2026
This vulnerability was fixed in PR #1926, merged on June 19, 2026. The
/api/video/aiendpoint now gates access throughPolicy.withPublicPolicy(videosPolicy.canView(videoId))before returning any metadata - you can see the check atapps/web/app/api/video/ai/route.ts:38.The same PR also added
canViewchecks to the transcript, translate-transcript, and available-translations endpoints, plus rate limiting on the translation endpoint.For self-hosted deployments: pulling the latest
mainbranch or any release after June 19, 2026 will include this fix.Related security work still in progress:
richiemcilroy commentedon Aug 3, 2026
Fixed by #1926 (merged June 19, 2026). The /api/video/ai endpoint now gates access through Policy.withPublicPolicy(videosPolicy.canView(videoId)) before returning any AI metadata, so cross-user reads of private video metadata are rejected. Closing.