debugger statement

Vulnerability potential Low
DDoS potential None

debugger pauses execution under devtools and should be removed from shipped code

Impact

The debugger statement is a programmatic breakpoint: when a debugger (such as browser DevTools or the Node inspector) is attached, reaching the statement halts execution there; with no debugger attached it is a no-op. Left in shipped code it is dead weight at best, and a real annoyance at worst — anyone who opens DevTools on the page (developers, QA, curious users, security researchers) has their session frozen at that line, the UI stops responding, and it looks like the application has hung. It signals unfinished work and erodes trust in the build. The statement should never reach production; it belongs to an interactive debugging session and should be removed before commit or stripped by the build.

Vulnerability potential

debugger has essentially no offensive security relevance: it does not execute attacker input, leak data, or corrupt state, and it only does anything when a developer has voluntarily attached a debugger. The two minor notes are that it is sometimes used deliberately in an infinite loop as an anti-analysis trick to frustrate researchers inspecting a page (a nuisance, not a vulnerability of the host application), and that its presence reveals the code was shipped without a proper build/lint gate. Neither rises above Low.

Technical details

debugger is a standard ECMAScript statement (the spec calls it the Debugger Statement). Its defined behaviour is implementation-dependent: if a debugger is present and active it should break, otherwise it has no observable effect. There is no way to “trigger” it without an attached debugger, which is exactly why it is harmless when no one is debugging and disruptive the moment someone is.

Build-time handling

In practice it should never survive into a release bundle. Most bundlers strip it automatically in production mode — Terser/UglifyJS remove debugger when the drop_debugger compress option is on (the default), and esbuild/SWC drop it under their minify settings. Relying on that is acceptable as a safety net, but the statement should still not be committed.

Distinguish from logging

Unlike a stray console.log, debugger actively pauses the program, so its impact when it slips through is more visible and more disruptive than a leftover log line.

Catching the issue

Linters

ESLint’s no-debugger rule is in eslint:recommended and flags every debugger statement; run it as an error in CI so a build fails rather than ships the statement. Biome’s noDebugger does the same.

Build and CI

Enable drop_debugger (Terser) or the equivalent minify option so production bundles are stripped even if one slips past review, and add a pre-commit hook or CI grep as a backstop. Keep the lint rule as the primary gate so the issue is caught at author time, not just removed silently at build time.

Review

Treat any committed debugger as a defect; it has no place outside a live debugging session.

How to reproduce

Run this with DevTools or the Node inspector open (node inspect file.js) and observe execution pausing at the debugger line; with no debugger attached it runs straight through.

function handleClick() {
  const value = compute();
  debugger; // execution halts here when DevTools is open
  return value;
}

function compute() { return 42; }