{"record":{"id":"7dd3b46cbbe1137f","repo":"Max-Eee/NeoPass","slug":"you-bad","errorCode":null,"errorMessage":"You bad!","messagePattern":"You bad!","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"data/inject/anti-anti-debug.js","lineNumber":128,"sourceCode":"\n    window.console.clear = wrapFn(() => {\n        if (shouldLog(\"table\")) {\n        }\n    }, Originals.clear);\n\n    let debugCount = 0;\n    window.Function.prototype.constructor = wrapFn((...args) => {\n        const originalFn = Originals.functionConstructor.apply(this, args);\n        var fnContent = args[0];\n        if (fnContent) {\n            if (fnContent.includes('debugger')) { // An anti-debugger is attempting to stop debugging\n                if (shouldLog(\"debugger\")) {\n                }\n                debugCount++;\n                if (debugCount > 100) {\n                    if (shouldLog(\"debuggerThrow\")) {\n                    }\n                    throw new Error(\"You bad!\");\n                } else {\n                    setTimeout(() => {\n                        debugCount--;\n                    }, 1);\n                }\n                const newArgs = args.slice(0);\n                newArgs[0] = args[0].replaceAll(\"debugger\", \"\"); // remove debugger statements\n                return new Proxy(Originals.functionConstructor.apply(this, newArgs),{\n                    get: function (target, prop) {\n                        if (prop === \"toString\") {\n                            return originalFn.toString;\n                        }\n                        return target[prop];\n                    }\n                });\n            }\n        }\n        return originalFn;","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/Max-Eee/NeoPass/blob/a0944782ceb8cb93fce3f651d94dcd6f63d927b9/data/inject/anti-anti-debug.js#L110-L146","documentation":"This library hooks window.Function.prototype.constructor and intercepts any dynamic function whose source contains a 'debugger' statement — a common anti-debugging trick used by scripts to break DevTools. Normally it silently strips the debugger statement out, but it keeps a rolling counter (debugCount) that increments on each detection and decays via setTimeout after 1ms. If more than 100 debugger-bearing functions are constructed within that window, it throws new Error(\"You bad!\") as an explicit signal that aggressive anti-debugging code is running.","triggerScenarios":"Constructing more than 100 functions via new Function(...) or Function(...) whose source text includes the substring 'debugger' within a ~1ms decay window (debugCount > 100). Example: new Function('debugger; return 1') called in a tight loop, or any obfuscation/bundler-generated code that repeatedly emits debugger statements through the patched Function constructor.","commonSituations":"Running the page with this anti-anti-debug injection active while a site's own obfuscated anti-debugging loop (e.g. the classic setInterval + Function('debugger') guard) fires rapidly; bundling/minifying code that contains many debugger statements; leaving leftover debugger statements in production code; debugging tools or test harnesses that dynamically build functions containing 'debugger'.","solutions":["Remove or reduce debugger statements in dynamically constructed functions — the counter only triggers when they contain the literal substring 'debugger'.","Space out or batch Function() constructions so fewer than 100 debugger-bearing calls occur before debugCount decays (setTimeout decrements it after ~1ms).","Use eval or another evaluation path that does not go through the patched Function.prototype.constructor if you legitimately need debugger statements.","In DevTools, use the 'Deactivate breakpoints' setting instead of emitting debugger statements from code.","Patch or disable this injection script's throw at data/inject/anti-anti-debug.js:128 if it is your own tooling firing on benign code."],"exampleFix":"// before\nfor (let i = 0; i < 500; i++) {\n  new Function('debugger; return ' + i)();\n}\n// after\nfor (let i = 0; i < 500; i++) {\n  new Function('return ' + i)(); // no 'debugger' substring, no counter increment\n}","handlingStrategy":"try-catch","validationCode":"const src = 'debugger; return 1';\n// avoid the error entirely: strip the debugger substring before invoking the patched constructor\nif (src.includes('debugger')) {\n  src = src.replaceAll('debugger', '');\n}\nnew Function(src);","typeGuard":"function isDebuggerFreeFnSource(src) {\n  return typeof src === 'string' && !src.includes('debugger');\n}","tryCatchPattern":"try {\n  const fn = new Function(source);\n} catch (e) {\n  if (e && e.message === 'You bad!') {\n    // anti-anti-debug guard tripped: strip debugger statements and retry\n    const fn2 = new Function(source.replaceAll('debugger', ''));\n  } else {\n    throw e;\n  }\n}","preventionTips":["Never ship literal 'debugger' statements in dynamically generated function source strings.","Use DevTools breakpoint settings rather than debugger statements for debugging.","Keep a linter rule (e.g. ESLint no-debugger with error severity) to catch debugger statements before build.","If you must evaluate debugger-bearing source, route it around the patched Function.prototype.constructor or sanitize the source first.","When testing code that legitimately loops Function('debugger'), disable the anti-anti-debug injection in your test environment."],"tags":["anti-debugging","debugger-statement","function-constructor","instrumentation"],"backgroundTag":"anti-debugger-loop-detected","analyzedSha":"a0944782ceb8cb93fce3f651d94dcd6f63d927b9","analyzedAt":"2026-08-31T13:12:32.887Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}