Introduction

Debuggers are invaluable tools when analyzing JavaScript, especially when dealing with obfuscated code and client-side protections. Developers and security researchers rely on them to understand how a web application functions, uncover vulnerabilities, or bypass restrictions.

Issue

However, many companies and developers implement anti-debugging techniques to make reversing their code more difficult. They inject scripts that detect when the browser is in debug mode, use obfuscation tricks, or even forcefully disable breakpoints. This makes the process of analyzing JavaScript incredibly frustrating, especially when dealing with proprietary protections or security mechanisms designed to prevent reverse engineering.

Anti-debugging detection message
Example of a typical anti-debugging detection

Disabling Breakpoints: A Simple but Limited Solution

A straightforward way to bypass some debugger detection mechanisms is to disable breakpoints entirely. This prevents JavaScript from pausing execution, making it harder for anti-debugging scripts to interfere.

Deactivating breakpoints
Disabling breakpoints in Firefox Developer Tools

However, this method has a significant trade-off: it also disables the ability to analyze JavaScript execution effectively. While this might work in some cases, it is not an ideal solution for deeper analysis, as losing the ability to set breakpoints severely limits our ability to inspect variables, modify execution flow, or analyze how the code behaves in real-time.

Renaming the Debugger in Firefox’s Source Code

⚠️ Important Note: This technique should only be used for legitimate security research, software development, and authorized testing. Unauthorized reverse engineering may violate terms of service or legal requirements.

The main issue with debugging restrictions is that websites rely on specific methods to detect the debugger’s presence. By changing the internal name of the Firefox debugger within the source code, we can bypass these detection mechanisms without losing debugging functionality.

Getting Firefox’s Source Code and Building It (macOS Instructions)

For detailed documentation, refer to:
🔗 Firefox Source Docs

1. Install Xcode

Download and install Xcode from the App Store. Then finalize the installation in your terminal:

$ sudo xcode-select --switch /Applications/Xcode.app
$ sudo xcodebuild -license

2. Install Mercurial

Mercurial is required to fetch the Firefox source code:

$ python3 -m pip install --user mercurial

3. Bootstrap a Copy of the Firefox Source Code

Run the following commands to get a local copy of the source:

$ curl https://hg.mozilla.org/mozilla-central/raw-file/default/python/mozboot/bin/bootstrap.py -O
$ python3 bootstrap.py

⚠️ Warning: Downloading the Firefox source code requires approximately 15GB of disk space and may take some time depending on your internet connection.

4. Configure Build Settings

When running the bootstrap script, you’ll be prompted to choose various configuration options:

$ python3 bootstrap.py

When running the bootstrap script, you’ll be prompted to select various configuration options. Follow the instructions and confirm the installation of required tools or dependencies.

4. Build and Run Firefox

Once configuration is complete:

$ cd mozilla-unified
$ hg up -C central
$ ./mach build

For reference, building Firefox took approximately 30 minutes using a system with 10 CPU cores and 32 GiB RAM.

After the build completes successfully, you can run the modified Firefox using:

$ ./mach run

After a successful build, you can find your compiled Firefox at:

obj-aarch64-apple-darwin*/dist/Nightly.app

*Note: The exact path may vary depending on your system architecture and version.

Editing the Source Code

Now comes the most interesting and surprisingly simple part: modifying the Firefox source code to rename the “debugger” keyword. To achieve this, I searched through the source code for all occurrences of “debugger”, compiled the browser multiple times, and identified the exact locations that needed to be changed. The goal was to rename the debugger internally to “debuggy” so that anti-debugging scripts would no longer detect it.

The changes were made in the following two files:

  • mozilla-unified/js/src/frontend/ReservedWords.h
  • mozilla-unified/js/src/vm/CommonPropertyNames.h

Here are the 2 changes that need to be made:

diff --git a/js/src/frontend/ReservedWords.h b/js/src/frontend/ReservedWords.h
--- a/js/src/frontend/ReservedWords.h
+++ b/js/src/frontend/ReservedWords.h
@@ -20,7 +20,7 @@
   MACRO(catch, catch_, TokenKind::Catch)                                  \
   MACRO(const, const_, TokenKind::Const)                                  \
   MACRO(continue, continue_, TokenKind::Continue)                         \
-  MACRO(debugger, debugger, TokenKind::Debugger)                          \
+  MACRO(debuggy, debugger, TokenKind::Debugger)                          \
   MACRO(default, default_, TokenKind::Default)                            \
   MACRO(delete, delete_, TokenKind::Delete)                               \
   MACRO(do, do_, TokenKind::Do)                                           \
diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -129,7 +129,7 @@
   MACRO_(daysInMonth, "daysInMonth")                                           \
   MACRO_(daysInWeek, "daysInWeek")                                             \
   MACRO_(daysInYear, "daysInYear")                                             \
-  MACRO_(debugger, "debugger")                                                 \
+  MACRO_(debugger, "debuggy")                                                 \
   MACRO_(decimal, "decimal")                                                   \
   MACRO_(decodeURI, "decodeURI")                                               \
   MACRO_(decodeURIComponent, "decodeURIComponent")                             \

With the modifications in place, I rebuilt the browser using the same build command (it takes 15 seconds this time :D).

Results: Debugger Detection Bypassed!

As shown below, an anti-debugging script fails to detect our modified debugger keyword:

Unrecognized debugger keyword
The original 'debugger' keyword is no longer recognized

The website’s protection now fails to detect debugging:

Bypassed protection
Anti-debugging protection successfully bypassed

And our debugger still works perfectly, just under a different name:

Modified debugger
Our debugger working with the new 'debuggy' keyword

Conclusion

By renaming the debugger internally in Firefox’s source code, we successfully bypassed JavaScript anti-debugging techniques while maintaining full debugging functionality. Unlike simply disabling breakpoints—an approach that limits further analysis—this method allows uninterrupted debugging without triggering protections.

Edit: 10/02/25

A friend needed a compiled version for Intel Mac, so I cross compiled it.

For detailed documentation, refer to: 🔗 Firefox Cross-Compilation Guide

I edited the .mozconfig file and added the following lines:

ac_add_options --target=x86_64-apple-darwin
ac_add_options --enable-bootstrap

After recompiling, I successfully built an Intel Mac version!

Download Pre-Compiled Versions

For convenience, I’ve made the modified versions of Firefox Nightly available for macOS:

🔹 Apple Silicon (ARM64) Version: 📥 Download Nightly_aarch64.tar.xz

🔹 Intel Mac (x86_64) Version: 📥 Download Nightly_x86_64.tar.xz