Skip to content

fix(infra): refuse a URL transcript source that is not media from its first bytes - #4150

Merged
richiemcilroy merged 5 commits into
mainfrom
fix/infra-transcript-url-sniff
Nov 13, 2026
Merged

richiemcilroy merged 5 commits into
mainfrom
fix/infra-transcript-url-sniff

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Nov 13, 2026 •

Copy link
Copy Markdown
Member

A transcript created from a URL that does not point to an audio or video file now fails as soon as its first bytes arrive. Before, Cap downloaded and stored the whole file, up to 2 GB, before failing it. The failure code and message are unchanged, and it is still never charged.

What changed

After the credit hold and before anything is stored, the download reads the first 4 KB of the response. It runs the same check that extraction already runs on the stored file (sniffMedia). If those bytes are not a self-contained audio or video file, such as an HTML page, a playlist or anything else, the download is cancelled and the transcript ends with unsupported_format and "The file is not a supported audio or video format". Otherwise the bytes that were read are passed back in front of the rest of the stream, so the stored file is identical.

  • An empty response still ends with source_unreachable, as before.
  • Upload sources are unchanged. They are still checked when extraction starts.
  • The check after storing stays, so a file is never extracted unless it passed.

Measured

Each failing source was run through the real download step, with a local origin that sends the file as fast as it is read:

Source Main: read from origin Main: stored This change: read This change: stored
2 GB declared, not media 2,147,483,648 bytes 2,147,483,648 bytes 48,825 bytes 0
100 MB declared, not media 104,857,600 bytes 104,857,600 bytes 65,366 bytes 0
40 KB HTML page 40,000 bytes 40,000 bytes 40,000 bytes 0
2 GB video with no audio track 2,147,483,648 bytes 2,147,483,648 bytes unchanged unchanged

The check needs 4 KB. The tens of kilobytes read are the first network chunks the HTTP client delivers before the connection is cancelled. On main the 2 GB case took 0.58 s locally to fail; with this change it fails in 0.01 s.

Proof

What Result
New download tests run against main's workflow 3 fail (HTML page, playlist, random bytes are stored before failing)
The same on this branch 12 of 12 pass, including a media file stored byte for byte, one shorter than 4 KB, and an empty response
Developer, infra and agent unit suites 2,108 pass
Real MySQL scratch database transcripts and holds suites 32 of 32
Typecheck and Biome clean, apart from one known unrelated typecheck error

The download tests' fake origin now starts its file with an MP3 tag so that it counts as media, and the test mocks of the media check keep the real sniffMedia.

Not covered

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge.

Summary

URL transcripts now check their first 4 KB before storing the download.

  • URL transcript downloads reject non-media sources before storing them.

No actionable issues were found. This review checked source code; it did not run tests.

Reviews (1) · Last reviewed commit: "test(infra): cover URL sources refused f..." · Reviewed by Greptile

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

@sandchest-com

sandchest-com Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Sandchest

Sandchest reviewed 64dcef3: nothing exploitable found in this change.

Sandchest reviews every change for vulnerabilities an attacker could use · 6 credits · Review details

@vercel

vercel Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
cap-status Skipped Skipped Nov 13, 2026 4:31am UTC

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

Open in Capy

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

Open in Capy

@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 04:31 Inactive

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

Open in Capy

@richiemcilroy
richiemcilroy merged commit 97d3df9 into main Nov 13, 2026
39 checks passed

This branch was successfully deployed

1 active and 1 inactive deployments
Preview – cap-web — 64dcef35 Deployed Nov 13, 2026 by vercel[bot]
Preview – cap-status — 64dcef35 Deployed Nov 13, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants