Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

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

Copy link
Copy link
@KIM-DONGJU

Description

@KIM-DONGJU
Issue body actions

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.

Reactions are currently unavailable

Metadata

Metadata

Assignees

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

    Projects

    Status
    Waiting for: Product Owner
    Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.