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.
| 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(', ')}`);