Every browser tool that says "nothing leaves your tab" is asking you to take its word for it. You can check instead.
I work on OnePassApps. Our File Studio has a hash tool, and it claims your file is never uploaded. So I attached the Chrome DevTools Protocol to a real tab, dropped in a 12 MiB file, ran the hash, and read every request the page made while it worked.
The result: zero requests carried a body.
The claim, in the tool's own words
Open File Studio, pick the File hash tab, and the panel reads:
- "Drop a file to hash, or browse"
- "One file of any type, up to 2 GiB · read on this device"
- "SHA-256 is the common choice for published checksums."
- "Compare with a trusted checksum"
- "Paste the checksum published by the source."
- "On this device. The file is never uploaded."
The page also states "Nothing leaves this tab." and "Processing stays in this browser.", and the File Studio intro says your files stay in this tab.
How to watch the network yourself
The quick way is DevTools: open the tool, open the Network panel, tick Preserve log, load your file, run the tool, then read the request list. Every row should be a GET, no row should have a request body, and no URL should carry your filename, size or bytes.
The sturdier way is to drive it over the protocol, because the raw request objects include postData and you can count it yourself. This is the shape of the script I used:
// create a tab on the studio route, attach to it, turn the network domain on const t = await send('Target.createTarget', { url: 'https://app.onepassapps.com/studios/files' }); const att = await send('Target.attachToTarget', { targetId: t.result.targetId, flatten: true }); const sid = att.result.sessionId; await send('Network.enable', {}, sid); // ...clear the log, load the file, click the action button, wait for the result... // then count what went out const reqs = events.filter(e => e.method === 'Network.requestWillBeSent').map(e => ({ method: e.params.request.method, url: e.params.request.url, bodyBytes: e.params.request.postData ? e.params.request.postData.length : 0, })); const withBody = reqs.filter(r => r.bodyBytes > 0); What actually went over the wire
Here is the log from my run, hashing a 12 MiB file:
REQUEST_COUNT: 4 HOSTS: {"app.onepassapps.com":1,"api.onepassapps.com":3} GET https://app.onepassapps.com/assets/file-worker-D73n2Oxs.js GET https://api.onepassapps.com/api/runtime GET https://api.onepassapps.com/api/config/feature-flags GET https://api.onepassapps.com/api/config/feature-flags REQUESTS_WITH_BODY: 0 Four requests, all GET, none with a request body. One is the page's own worker bundle, one is the runtime endpoint, two are the feature-flag config. Nothing in that list carries a file, a filename or a byte of the file.
The digest proves the file was really read
A hash tool that never read your file would be a hash tool with nothing to hash. So the checksum itself has to check out. I hashed the same file in the shell:
$ sha256sum local-proof-big.bin ab5b4ebf033cb33d7530f9ab38633fd1c024cc87250e7ae31f6d7ebb232daa0e local-proof-big.bin The app's result panel showed the same 64 hex characters, and its size line read "Exact size 12,582,912 bytes", which is the byte count of the file on disk. So the tool read all 12 MiB and produced the standard SHA-256 of those bytes, and it did it without putting a single byte in a request body.
What this does and does not prove
It proves that, for this tool, in this browser, the file was read locally and was never sent in a request body.
It does not prove the tool is bug-free, that every other tool behaves identically, or that nothing about you leaks. Two of those GETs are ordinary application config calls, and the page itself is served to your browser like any other site. If a tool makes a privacy claim, the cheapest way to believe it is to watch the network while it runs.
The File Studio is where the hash tool lives, and the app guides explain what each studio does and what it will not do: File Studio and the guides.
One note on method: the panel offers a "Compare with a trusted checksum" box for checking a download against the checksum its publisher lists. I did not use that box in this run. I compared the app's output against sha256sum in the shell instead, so the two numbers above come from two independent implementations.