The Problem Nobody Talks About
Browser SRI (Subresource Integrity) has been around since 2016. It lets you verify that scripts loaded from CDNs haven't been tampered with:
<script src="https://cdn.example.com/lib.js"
integrity="sha256-abc123..."
crossorigin="anonymous"></script>
Here's the thing: SRI only works on <script> and <link> tags.
When you fetch() a file - a WASM module, an AI model, a JSON config, any binary data - you get zero integrity protection. The browser just... trusts it.
What Happens When a CDN Gets Compromised
In June 2024, polyfill.io was compromised. The CDN started serving malicious JavaScript to over 100 million websites.
Sites that used SRI on their script tags were protected. Sites that loaded polyfill.io via fetch() or dynamic import? Completely vulnerable.
This isn't a theoretical attack. It happened. And it will happen again.
Why Native Solutions Fail
You might think: "I'll just hash the response myself with crypto.subtle.digest()"
Try that with a 4GB AI model:
| File Size | Native crypto.subtle | VerifyFetch |
|---|---|---|
| 100 MB | Works | Works |
| 1 GB | Slow, RAM spike | 2MB memory |
| 4 GB | Browser crash | 2MB memory |
Native crypto buffers the entire file into memory before hashing. That's fine for small files, but completely unusable for large ones.
The Solution: VerifyFetch
I built VerifyFetch to fill this gap:
import { verifyFetch } from 'verifyfetch';
const response = await verifyFetch('/model.bin', {
sri: 'sha256-uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek='
});
If the hash doesn't match, it throws. Your users are protected.
How It Works
VerifyFetch uses a WASM streaming hasher compiled from Rust. Data flows through chunk by chunk - the file is never buffered entirely in memory.
The result: constant ~2MB memory usage whether you're verifying a 10MB file or a 10GB file.
It also includes:
- Fallback URLs: If verification fails, automatically try a backup server
- Progress tracking: Know exactly how much has been verified
- Manifest mode: One JSON file with all your hashes
- CLI for CI/CD: Fail builds if files change after signing
Generate Hashes
npx verifyfetch sign ./public/*.wasm ./models/*.bin
This creates a vf.manifest.json with all the SRI hashes.
Use in Your App
const vf = await createVerifyFetcher({
manifestUrl: '/vf.manifest.json'
});
// Hashes are looked up automatically
const model = await vf.arrayBuffer('/model.bin');
const config = await vf.json('/config.json');
Enforce in CI
npx verifyfetch enforce --manifest ./public/vf.manifest.json
Your deploy fails if any file has changed since signing.
Try It
npm install verifyfetch
GitHub: https://github.com/hamzaydia/verifyfetch
Docs: https://verifyfetch.com
I'd love feedback on the API design and any edge cases I might be missing.
Top comments (0)