How Proctor Content Scripts Work — and Why Browser AI Fails
Every modern coding-interview proctor — HackerRank, CoderPad, CoderPad Enterprise, CodeSignal, Karat — ships JavaScript that runs inside the candidate's tab. It is not hidden. You can see it in DevTools' Sources panel, attached as event listeners in the Event Listeners panel, and firing on every keystroke in the Performance panel. The code is signed, served from the platform's own origin, and watching for a small set of behavioral signatures that only an AI tool would produce.
This post is a vector-by-vector teardown of what the content script actually reads, why each primitive is one line of standard DOM API, and the architectural reason every browser-based AI interview tool fails the same chain. None of this is reverse engineering. It is plain DOM behavior most front-end engineers shipped a feature of last week.
Key takeaways
- A proctor's content script has access to six independent DOM APIs that, combined, fingerprint AI tool usage with high confidence:
keydown/keyup,paste,MutationObserver,visibilitychange,document.hasFocus, and (for browser-extension AI tools)chrome.runtime.id. - The signature most content scripts hunt for is modifier chord pressed without a corresponding editor mutation — Alt+Enter fires, no character lands, no caret moves. That asymmetry is one
ifstatement. - A native desktop overlay with a kernel-mode hotkey hook is the only architecture that defeats every primitive on this list. The browser never sees the chord, never loses focus, and never reports a missing extension because the tool does not exist inside the browser at all.
Browser extensions live in the DOM. The DOM is enumerable by the proctoring platform. Native desktop overlays live outside the DOM, outside the iframe sandbox, and outside the extension API.
If you would rather watch the same probes fire against any AI tool you already own, the /proctor test page runs the full set in your browser. No login. Five minutes.
What a content script can actually read
There is some confusion in candidate forums about the difference between a browser extension content script and an in-page content script. Worth clearing up before the vector list.
- In-page content script. A regular
<script>tag the platform serves from its own origin. Same access as any other script on the page. This is the one HackerRank, CoderPad, CodeSignal, and Karat all ship by default. It cannot read installed extensions or other tabs. - Browser-extension content script. A script injected by a sanctioned proctor browser extension. Same DOM access plus the extension API surface (
chrome.runtime,chrome.management.getAllif the user grants it). Used by some Enterprise customers under explicit consent.
The vector list below covers both. Most rounds run only the in-page script; the extension is the upgrade.
Vector 1 — keydown and keyup events
The single most-watched primitive. The script registers document.addEventListener('keydown', handler, {capture: true}) at the capture phase so it sees the event before the editor's own listener does. The handler reads event.altKey, event.ctrlKey, event.metaKey, event.shiftKey, and event.key. Every chord is logged with a millisecond timestamp (MDN: KeyboardEvent).
What that buys the proctor:
- The exact set of chords pressed during the round, with timing.
- Whether a chord was followed by an editor mutation (next vector). If not, that is the AI hotkey signature.
- A frequency count of common AI hotkey shapes — Alt+Enter, Ctrl+Shift+L, Cmd+K, Alt+1, Alt+2 — across a known fleet of tools.
This is the vector that catches Interview Coder. Public reports describe a candidate at Apple pressing the solve hotkey on a CoderPad round and the interviewer ending the call in the same minute (TeamBlind: "My Apple interview nightmare"). The browser saw the chord. There was nothing to engineer around once that primitive fires.
Vector 2 — MutationObserver on the editor surface
The script attaches a MutationObserver to the editor's content element with {childList: true, subtree: true, characterData: true} (MDN: MutationObserver). Every text insertion, deletion, or attribute change fires within microseconds.
The proctor correlates keydown events to mutations. Three patterns it watches for:
- One keypress, one character. Normal typing. No flag.
- One keypress, multi-line block. Paste-shaped insertion. Cross-checked against the next vector.
- Modifier chord, zero mutations. AI hotkey signature. Logged.
The third is the giveaway. A real human pressing Alt+Enter in a code editor either inserts a newline or triggers a known editor command (autocomplete, suggestions). An AI tool's hotkey produces no editor effect at all because the chord was meant for a different process. The content script does not need to know which AI tool you are using. It only needs to know that the chord happened and the editor stayed silent.
Vector 3 — paste events with content fingerprinting
document.addEventListener('paste', …) exposes the entire pasted payload through event.clipboardData.getData('text/plain') (MDN: ClipboardEvent). The script hashes the content client-side, sends the hash to the platform, and the platform compares it server-side against a corpus of known LLM outputs.
CodeSignal IQ, CoderPad's fairness toolkit, and HackerRank's full-screen mode all run this vector. The corpus is built by running every major model through the platform's own problem set during the prior year. A match score over a threshold writes into the recruiter-facing fairness report.
What this vector specifically catches: AI tools that auto-paste model output into the editor. The pasted block is a verbatim hit. Even if the model is rotated each release, generated code carries pacing and structural fingerprints — uniform spacing, single-pass variable naming, no scratched-out attempts — that a humanizer pass barely dents.
Vector 4 — visibilitychange and focus deltas
Two related primitives:
document.addEventListener('visibilitychange', …)fires whenever the tab becomes the foreground tab or backgrounded (MDN: visibilitychange).document.hasFocus()and thewindowblur/focusevents give millisecond-resolution data on whether the tab still holds keyboard focus.
What that catches: any AI overlay that grabs focus when invoked, even briefly. A 200-millisecond focus blur immediately preceding a 50-line correct solution is the most damning shape in any fairness report. It is also the failure mode that quietly disqualifies most browser-extension AI tools and BrowserWindow-style Electron overlays — they did not know they were costing the candidate the IDE focus, but the content script saw every transition.
The consumer CoderPad surfaces the focus-loss count as a number to the recruiter. CoderPad Enterprise feeds the timeline into the fairness report. HackerRank polls document.hasFocus() at roughly 200ms intervals and logs every transition with a timestamp. The data is durable; the recruiter can replay the focus timeline alongside the editor mutation log and watch the two correlate.
Vector 5 — clipboard read/write surface
The Clipboard API (MDN: Clipboard) gives a content script access to clipboard reads when the user grants permission, and to clipboard writes universally during a cut/copy event. Most proctor scripts do not request read permission (it would prompt the user) but they do listen for copy events to log what the candidate copied out of the editor.
The asymmetric case: an AI tool that uses the clipboard as its IPC channel — write a problem statement to the clipboard, read it back from a separate process, write the solution back, paste it in. Every step that touches the page produces an event. Clipboard-driven AI tools were popular in 2023. They light up like a Christmas tree on any 2026 proctor.
Vector 6 — extension enumeration (when the proctor extension is present)
This vector only fires when the candidate has consented to a sanctioned proctor browser extension. When it does, the proctor calls chrome.runtime.id against a list of known AI-tool extension IDs, or — with the right manifest permission — chrome.management.getAll to list every installed extension by ID and name (Chrome Extension API: management).
What it catches: every browser-extension AI tool, by definition. Cluely's overlay reportedly fails this vector when it falls back to its browser companion. Final Round AI's extension is enumerable. So is every Sensei AI / Coderpilot / Interview Solver in the same architectural class. Extension fingerprinting is why our 2026 stealth audit of 14 tools graded the entire browser-extension category RED across the board.
What you can see yourself in DevTools
You do not have to take any of this on faith. Open DevTools on a HackerRank or CoderPad assessment page. Switch to the Sources panel. Look for the platform's own JS bundle (filenames typically include proctor, fairness, assessment, or monitor). In the Event Listeners panel under the document node, you will see attached keydown, paste, visibilitychange, and blur listeners. None of it is obfuscated past the standard webpack minification.
The Performance panel will record every fired listener during a recorded session. Capture 30 seconds of typing, pause to switch windows, paste a snippet, and you will see each event fire with its handler stack. This is the same data the platform's server is receiving over the wire after each event.
Why every browser-based AI tool fails the same chain
Architecturally, a browser-based AI tool has three deployment shapes, and each one trips a specific subset of the vectors above:
- Browser extension overlay. Trips Vector 6 (extension enumeration) immediately when present, plus Vectors 1 and 2 if it ships a hotkey, plus Vector 4 if it grabs focus when invoked.
- In-page injected
<iframe>overlay. Visible toMutationObserver(Vector 2), enumerable in the page's iframe list, and the hotkey still fires through the page'skeydownlistener (Vector 1). BrowserWindowElectron / web app overlay. Avoids Vector 6 but still fires Vector 4 (window focus delta) and Vector 1 (any global hotkey leaks into the page on Windows because the OS dispatcheskeydownto the foreground process before any IPC).
The category-level conclusion: any AI tool that lives inside the browser, near the browser, or in a process that can lose IDE focus when invoked is detectable on a 2026 proctor. The fix is not a bug fix. It is a different architecture.
What architecturally evades each vector
A native Windows overlay with a kernel-mode hotkey hook is the only configuration that defeats the whole list. Walking the same primitives:
- Vector 1 —
keydown. The kernel-mode keyboard hook intercepts the chord before the user-mode browser ever receives the input. The page's listener never fires. There is no event for the content script to read. This is the load-bearing primitive; if you understand only one thing about ring-0 stealth, understand this one. - Vector 2 —
MutationObserver. Memory read pulls problem and code from IDE/browser process memory directly, with no editor-side mutation, no auto-paste, no DOM touch. The observer fires nothing. - Vector 3 —
paste. Memory read replaces the clipboard path entirely. Nothing pastes. Nothing for the corpus matcher to hash. - Vector 4 —
visibilitychangeand focus. The overlay is stripped from the display pipeline before any capture path can reach it, and the window is non-focusable by default (WS_EX_NOACTIVATEplus kernel-level concealment). The IDE never receivesWM_KILLFOCUS. There is no focus delta in the timeline. - Vector 5 — clipboard. Same answer as Vector 3. The IPC channel does not touch the clipboard.
- Vector 6 — extension enumeration. No extension exists. The tool is not in the browser at any layer.
chrome.management.getAllreturns the same list it would on a candidate machine running no AI tool at all.
For the engineering depth on each layer — kernel display-pipeline strip, process concealment, window-enumeration filtering, detection-query spoofing — see our tour of the four stealth layers and the ring-0 memory read versus screenshot OCR post that explains why the input side matters as much as the output side.
For platform-specific failure modes, the CoderPad Enterprise teardown walks the same primitives in the context of the most aggressive proctor surface in the category.
How to verify any of this against your own setup
Three minutes, no commitment:
- Open /proctor in the browser you would interview from.
- Start your AI tool in its normal configuration. Press its hotkey, paste any sample, switch focus to the tool's window if it has one.
- Watch which probes light up. The probes are the same DOM primitives a real proctor's content script reads. If a vector flags on /proctor it will flag on HackerRank, CoderPad, or CodeSignal too.
The point is to fail-fast in your own browser, days before the round. The cost of finding a leak now is zero. The cost of finding one mid-interview is the offer.
FAQ
Is the proctor's content script obfuscated or hidden? No. It is shipped as a standard JS bundle from the platform's origin, minified but not obfuscated, and the listeners are visible in DevTools' Event Listeners panel. The platforms do not need to hide it because the primitives it uses are platform-supported DOM APIs — there is nothing to hide.
Can I block the content script with an ad blocker or Content-Security-Policy override?
The platform's own CSP serves the script from its origin. Blocking it breaks the assessment page; the platform's frontend depends on the same bundle. Some candidates have tried; the fairness report flags "proctor monitor failed to load" as a hard fail.
Does turning off my webcam disable any of these? No. Webcam vectors are separate (Vectors 4 and 5 of HackerRank's own six-vector stack). The six DOM primitives above all run with no camera, no microphone, no extension, on the cheapest free assessment.
Why does my AI tool's hotkey still fire if it claims to be "global"?
On Windows, "global" hotkeys are usually registered with RegisterHotKey from user32, which receives the chord after the foreground window's input queue. The browser is the foreground window. The browser's keydown listener fires first. Most AI tools that say "global" are trapping the chord in user mode after the page already saw it. A kernel-mode hook intercepts in the OS input stack before any user-mode process — including the browser — runs.
What about Mac?
Mac has analogous primitives — CGEventTap at the system level, NSEvent at the application level. The architectural picture is similar: a tool that hooks at the application level loses to a tool that hooks at the system level. We are Windows-only by design; we cannot speak to a specific Mac AI tool's depth.
If you have a HackerRank, CoderPad, or CodeSignal round on the calendar and you want the content script to see nothing unusual, FaangCoder is $399 lifetime (or $199/mo). The /proctor page is open to anyone before you commit. Run it against any tool — including ours.
