Skip to content

Console breadcrumb serialization invokes getters & DOM traversal on logged objects (regression in 10.55.0: safeJoin now uses stringifyValue instead of String) #21353

@KIM-DONGJU

Description

@KIM-DONGJU

Is there an existing issue for this?

  • I have searched the existing issues (no match for safeJoin / stringifyValue / console-breadcrumb getter side effects)
  • I have reviewed the documentation
  • I am using the latest SDK release (reproduces on 10.56.0)

How do you use Sentry?

Sentry SaaS (sentry.io)

Which SDK are you using?

@sentry/browser (root cause is in @sentry/core's safeJoin, surfaced via the Breadcrumbs integration; observed through @sentry/nuxt)

SDK Version

10.56.0 (regression introduced in 10.55.0; last unaffected version: 10.54.0)

Framework Version

Nuxt 4 / Vue 3.5

Reproduction Example/SDK Setup

import * as Sentry from '@sentry/browser'

// Default integrations include Breadcrumbs with console capturing enabled
Sentry.init({ dsn: '__YOUR_DSN__' })

const el = document.createElement('div')
let getterInvoked = false
Object.defineProperty(el, 'id', {
  get() {
    getterInvoked = true   // any side effect here now runs during console breadcrumb capture
    return ''
  },
})

console.log(el)            // Sentry's console breadcrumb handler serializes the args here
queueMicrotask(() => console.warn('getter invoked by Sentry serialization?', getterInvoked))
// @sentry/core <= 10.54.0  -> false
// @sentry/core >= 10.55.0  -> true  (incl. 10.56.0)

Steps to Reproduce

  1. Initialize any browser SDK with default integrations (Breadcrumbs console: true).
  2. console.log() an object that has a property getter (e.g. a DOM element, or any object with Object.defineProperty(..., { get })).
  3. Observe that the getter is executed synchronously as part of breadcrumb creation — even when DevTools is closed and no event is sent.

Expected Result

Capturing a console breadcrumb should be side-effect free: serializing the logged arguments for the breadcrumb message must not invoke user-defined property getters, nor traverse the DOM. (<= 10.54.0 behaved this way — non-primitive args were serialized with String(value).)

Actual Result

Getters are invoked and DOM elements are walked during breadcrumb serialization.

Root cause — @sentry/core safeJoin (packages/core/src/utils/string.ts), which the Breadcrumbs integration uses for the console breadcrumb message (message: safeJoin(handlerData.args, ' ') in _getConsoleBreadcrumbHandler):

  // <= 10.54.0
- } else {
-   output.push(String(value));     // "[object HTMLDivElement]" — no getters invoked
- }

  // >= 10.55.0
+ } else if (value instanceof Error) {
+   output.push(value.message ? `${value.name}: ${value.message}` : value.name);
+ } else {
+   output.push(stringifyValue(void 0, value));   // <- invokes getters
+ }

For DOM elements, stringifyValue resolves to htmlTreeAsString_htmlElementAsString (packages/core/src/utils/browser.ts), which reads elem.id / elem.className / elem.getAttribute(...) and walks the ancestor chain — executing getters and adding DOM-traversal cost to every console.log(element).

Additional Context

  • Real-world impact (how we found it): an anti-DevTools library uses the classic trap Object.defineProperty(div, 'id', { get() { /* assume DevTools open */ } }) followed by console.log(div), expecting the getter to fire only when DevTools renders the object. After upgrading @sentry/nuxt 10.53.1 → 10.55.0, Sentry's breadcrumb serialization began invoking that id getter on every page, causing a false "DevTools open" detection (and a forced redirect) with DevTools closed. We confirmed via a pristine (un-instrumented) iframe console.log that the getter is read only through the main-window Sentry-instrumented console.
  • Precedent that this class of bug is known/dangerous: safeJoin already special-cases isVueViewModel to avoid serialization side effects (the infinite console-warning loop fixed in fix(utils): Prevent iterating over VueViewModel #8981). Invoking arbitrary getters / DOM traversal is the same category of risk (side effects, performance, potential exceptions).
  • Affected range: 10.55.010.56.0 (latest). 10.54.0 and earlier are unaffected.
  • Suggestion: keep breadcrumb-message serialization side-effect-free for non-primitive args (e.g. retain String(value) for the human-readable message, since the structured data.arguments already carries the raw args for later normalization), or guard stringifyValue/htmlTreeAsString against invoking getters during breadcrumb capture.

Priority

React with 👍 to help prioritize this issue.

Metadata

Metadata

Assignees

No one assigned
    No fields configured for issues without a type.

    Projects

    Status
    Waiting for: Product Owner

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions