Skip to content

πŸ› Swagger UI mutates the global DOMPurify instanceΒ #10871

@michael-wolfenden

Description

@michael-wolfenden

Description

Swagger UI calls DOMPurify.addHook(...) on the global DOMPurify object. This is a side effect that leaks beyond Swagger UI's scope β€” any other code sharing the same DOMPurify instance will unexpectedly inherit the hook, which can cause subtle bugs or unintended behaviour in host applications.

Location

This occurs in src/core/components/providers/markdown.jsx.

Known impact

This is causing a bug in Backstage where the globally registered beforeSanitizeElements hook overwrites the rel attribute on any element with an href, including <link> stylesheet elements. As a result, stylesheet links have their rel="stylesheet" replaced with rel="noopener noreferrer", preventing stylesheets from loading and causing TechDocs pages to render as a blank white screen. See backstage/backstage#34037 (comment) for details.

Current behaviour

if (DomPurify.addHook) {
  DomPurify.addHook("beforeSanitizeElements", function (current) {
    if (current.href) {
      current.setAttribute("rel", "noopener noreferrer")
    }
    return current
  })
}

return DomPurify.sanitize(str, {
  ADD_ATTR: ["target"],
  FORBID_TAGS: ["style", "form"],
  ALLOW_DATA_ATTR,
  FORBID_ATTR,
})

Expected behaviour

Swagger UI should create a scoped DOMPurify instance using DOMPurify(), so hooks are registered only on that instance and the global object is never modified.

Proposed fix

const customDomPurify = DomPurify(window)

customDomPurify.addHook("beforeSanitizeElements", function (current) {
  if (current.href) {
    current.setAttribute("rel", "noopener noreferrer")
  }
  return current
})

return customDomPurify.sanitize(str, {
  ADD_ATTR: ["target"],
  FORBID_TAGS: ["style", "form"],
  ALLOW_DATA_ATTR,
  FORBID_ATTR,
})

This is the approach recommended by the DOMPurify docs for library authors β€” creating a fresh instance via DOMPurify(window) ensures hooks are scoped and do not pollute the global object.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions