wirebrowser

Tracing JavaScript Value Origins with Breakpoint-Driven Heap Search (BDHS) and Live Object Search

Modern JavaScript applications make a deceptively simple question extremely hard to answer:

Where does this value come from?

Between frameworks, bundlers, minifiers, async flows, closures, and virtual DOM abstractions, the origin and lifecycle of a value become opaque. You might see:

…with no visibility into where it was created or modified.

Traditional debugging tools weren’t designed for this reality.
Manual breakpoints, stepping, logs, or a single heap snapshot rarely help.

This writeup presents the techniques implemented in Wirebrowser, an open-source CDP-based toolkit:


1. Why Tracing Value Origins Is Hard in Modern JavaScript

Several factors obscure causality:

• Framework abstractions

React, Vue, Angular, Svelte, and others wrap user-land logic and hide real callsites.

• Bundlers and minifiers

Applications ship as giant anonymous bundles; stack traces are meaningless.

• Async flows

Promises, microtasks, events, timers, schedulers — traditional linear stepping cannot follow these cross-task transitions.

• Closures and hidden state

Values can live inside unreachable closures or internal structures.

• Static heap snapshots lack temporal information

A snapshot shows what exists now, not where or when it appeared.

Even trivial questions like “Where was this object created?” become difficult.


2. Breakpoint-Driven Heap Search (BDHS / Origin Trace)

BDHS turns heap snapshots into a temporal search space.

Instead of capturing one snapshot at an arbitrary moment, BDHS:

  1. Pauses execution automatically at meaningful boundaries.
  2. Captures a heap snapshot at each pause.
  3. Searches every snapshot for the target value or structure.
  4. Identifies the first snapshot containing it (origin in time).
  5. (Future) Detects when the structure or value changes across snapshots.
  6. Maps the origin back to the user-land function responsible, ignoring framework noise.

BDHS answers:

“When did this value first appear, and which user-land function introduced it?”

Even inside minified, async-heavy SPAs.


2.1 Event → Heuristic Handler Detection → Step-Out Execution

BDHS does not pause randomly or on every async boundary.
Instead, it follows this sequence:

  1. Install an initial breakpoint on a real user event (e.g., click).
  2. Attempt to identify the actual event handler for the event target using heuristics
    (Handler Detection). This is not fully deterministic but works in most real-world SPAs.
  3. Attach a breakpoint to the resolved handler.
  4. Execute with step-out stepping, pausing only at function returns.
  5. Capture a snapshot at each pause.

This yields a clean, semantically meaningful timeline aligned with:

Unlike traditional linear stepping, BDHS does not attempt to follow every instruction or every async boundary. Instead, it uses semantic step-out execution: it pauses only at meaningful user-land function boundaries, creating a sparse but highly informative temporal timeline.

Even though BDHS issues step-out commands sequentially, it does not produce a linear execution trace. Traditional stepping tries to follow the real instruction flow, including async jumps and framework internals. BDHS instead samples only meaningful user-land boundaries, creating a sparse, semantic timeline rather than a faithful step-by-step trace.


At each pause, BDHS calls HeapProfiler.takeHeapSnapshot.

Snapshots include:

BDHS searches each snapshot for:

Since snapshots contain everything, BDHS can locate:


2.3 Identifying Origins

When a match is found:

BDHS maps these events to the user-land function via:

BDHS identifies the function where the value was introduced—
not the exact line, due to CDP granularity and snapshot timing.
BDHS can also provide the snapshots immediately before and after the first match through the tolerance window, offering contextual insight into how the value is created or mutated.
BDHS therefore complements both static snapshot search and live object search: it provides the temporal dimension that neither of them can offer.

2.4 Tolerance Window (Snapshot Sampling Window)

The tolerance window expands BDHS by providing not only the snapshot where the target value first appears, but also the immediate execution context around it.

When BDHS detects the first match, it automatically:

Wirebrowser displays these snapshots in a chronological table, highlighting:

This contextual timeline makes it possible to understand:

The tolerance window dramatically increases BDHS’s diagnostic power, especially in asynchronous, framework-heavy SPAs where objects may be assembled over several steps.


3. Hybrid Structural Similarity Search

Wirebrowser includes a hybrid similarity engine for comparing JavaScript objects by structure and shape.

Pure SimHash performs poorly on small or sparse objects.
To address this, Wirebrowser uses a hybrid similarity metric combining:

The result is robust similarity detection for:

Similarity search is fully integrated across:

Find structurally similar objects in the live heap.

Identify clusters of similar objects inside snapshots.

✔️ BDHS (Origin Trace)

Use structural similarity as a search key across temporal snapshots.

This enables queries like:

Because the same similarity engine runs across live memory, snapshots, and BDHS timelines, investigations can seamlessly pivot between the three without changing query semantics.


4. Static Snapshot Search vs BDHS vs Live Objects

Wirebrowser offers three memory analysis modes:



BDHS / Origin Trace



5. Live Object Search and Runtime Patching

Live Object Search enables:

And supports live object patching:

Useful for:


6. Combined Workflow

The intended analysis workflow:

  1. Find a suspicious value (Live Object Search).
  2. Trace its origin (BDHS / function-level origin).
    2b. Use the tolerance window to inspect the snapshots before and after the origin, gaining contextual understanding of the value’s creation or mutation.
  3. Patch related objects to test hypotheses (Live Object Search).
  4. Validate by rerunning the scenario.

A cycle that traditional debugging cannot achieve:

find → trace → patch → validate


7. Concrete Examples

These scenarios show how BDHS, Live Object Search, and Hybrid Similarity Search work together in real investigations.


Example 1 — Tracing a JWT-like Value in a Request

A token-like string appears in an outgoing request. It doesn’t exist in globals, and DevTools shows only framework internals.

Workflow

  1. Trigger the UI action that generates the request.
  2. Use Live Object Search (regex) to find the value in memory.
  3. Reload the page to remove the value from memory.
  4. Start BDHS using the found value.
  5. BDHS performs heuristic handler detection, step-out stepping, and snapshot capture/search.
  6. The first snapshot containing the token maps to the user-land function assembling it.

Result

BDHS reveals logic hidden inside minified SPA bundles.


Example 2 — Finding Where a React Component State Becomes Invalid

A component occasionally enters an impossible state (loading: true + error: true).

Workflow

  1. Trigger the problematic UI action once.
  2. BDHS:
    • attempts heuristic handler detection
    • executes step-out stepping
    • captures snapshots at each boundary
  3. BDHS searches snapshot-by-snapshot using patterns and similarity.
  4. The earliest snapshot with the invalid structure reveals the responsible reducer function.

Result

Something stepping cannot catch becomes visible immediately.
With the tolerance window, BDHS also reveals the snapshots preceding the invalid state, making it clear which function prepares the inconsistent data before the reducer sets the final state.


Example 3 — Tracing a Tainted String in a DOM-Based XSS Case

A dangerous string appears in a DOM sink.

Workflow

  1. Copy the tainted string.
  2. Use Live Object Search to find all occurrences in memory.
  3. Run BDHS on one instance.
  4. BDHS identifies when the string first appears in snapshots.
  5. The origin maps to the user-land function that introduced it.

Result

Effective for DOM XSS incident response.


Example 4 — Reverse Engineering a Minified SPA

A hidden boolean flag controls anti-bot behavior.

Workflow

  1. Use Live Object Search to locate the flag and similar objects.
  2. Start BDHS.
  3. BDHS traces the first appearance of the flag.
  4. Mapping reveals a small region in a huge minified file.

Result

The investigation narrows from ~200k lines to ~20.


Example 5 — Using Structural Similarity to Trace Complex Objects

A component generates slightly varying nested configuration objects.

Workflow

  1. Locate an instance via Live Object Search.
  2. Use Similarity Search to find structurally similar objects.
  3. Run BDHS using the similarity signature as a search key.
  4. The first snapshot containing any object of that “shape family” reveals the origin.

Result

BDHS + similarity find origins even for evolving object families.


Example 6 — Tracing Runtime-Generated Code Paths

Some SPAs generate handlers dynamically with closures.

Workflow

  1. Find the handler via Live Object Search (by pattern or similarity).
  2. Run BDHS on the function object.
  3. BDHS finds the first snapshot containing the function (including closure environments).
  4. Mapping identifies the factory function responsible.

Result

BDHS handles what DevTools cannot.


8. Future Work

Building on the current foundation:

• Object Lifecycle Diffing

Compare similarity across BDHS snapshots to visualize evolution.

• Mutation Tracking in Snapshots

Detect meaningful structural changes over time.

• Flow Debugger

A temporal visualization combining BDHS, snapshots, and similarity deltas.

• Cross-Modal Correlation

Correlate network payloads with memory objects via similarity.

• Automated SPA Crawling

Explore SPAs while attaching BDHS and Live Object Search to each action.

• Deeper Framework Blackboxing

More robust heuristics for ignoring framework internals in single-file bundles.

• Adaptive tolerance window

Heuristics that automatically adjust the sampling range based on object complexity or execution patterns.


9. Closing Notes

Breakpoint-Driven Heap Search, Hybrid Similarity Search, and Live Object Search provide a new way to analyze JavaScript:

Wirebrowser makes these techniques practical in real-world, framework-heavy, async-intensive applications.

Contributions and feedback are welcome.


10. Resources

• Wirebrowser Repository

https://github.com/fcavallarin/wirebrowser

• BDHS + Live Object Search Demo Video

https://www.youtube.com/watch?v=WA5nHk-6UJc

• Documentation / Writeups

This document is part of the Wirebrowser technical documentation inside the docs/ directory.