Security check

A secret is generated when this page loads, handed straight to the element, and never written anywhere else. Then every surface a scraper, an agent or a reader-mode extension can reach gets searched for it.

Why there is no text box here

Every other page on this site lets you type the secret, which is convenient and quietly ruins the test. A value you typed lives in input.value, and that is a surface of its own: it survives View Source, it is invisible to innerText, and querySelectorAll('input') hands it over instantly. The audit correctly reported a leak, the leak was the demo's own text box, and a check that always fails for a reason you have to explain away is not evidence of anything.

So this page has no field. The value comes from fakeLike(), exists only as a JavaScript local, goes to el.secret, and is passed to auditPage() to be searched for. It is never rendered as text, so it is never shown to you either. You get its shape and its length, which is what you need to trust the search without the page having to leak it to prove itself.

Reload for a different one. The format rotates and the digits are random, so a pass cannot be one lucky string that happens not to appear anywhere.

This load's secret …
running…

The canvas row is the honest one and it never says "clean". The canvas has to hold the correctly arranged image or you could not read it either, so a run of frames averaged together is the plaintext. No mode changes that, and reporting it as safe would be a lie. Both attacks below run for real.

How DevTools defeats it

Listing a defeat without showing it invites the assumption it is theoretical.

scramble blunts the one line fillText dump and keeps the value out of a heap search, but it is obfuscation rather than encryption. The real line is automated pipeline against targeted attacker. nocap defeats the pipeline. It never defeats the person who has decided to come after the value, because the client belongs to them.

Run this on your own page

The table above is not special to this demo. It is the same auditPage() the library exports, which is there so you can check an integration rather than take the claim on trust.

import { auditPage } from 'nocap-js';

const report = await auditPage(secret);
console.log(report.report);
if (!report.clean) throw new Error(`leaked in ${report.found.join(', ')}`);
It takes the plaintext, because it has to search for it. That puts the value in one more place while the call runs, so use it in development and in tests, not in a production render path.