Skip to content

RS-22753: Allowlist Font Awesome CDN link in Box sanitiser - #54

Merged
chschan merged 5 commits into
masterfrom
RS-22753
Jul 2, 2026
Merged

RS-22753: Allowlist Font Awesome CDN link in Box sanitiser#54
chschan merged 5 commits into
masterfrom
RS-22753

Conversation

@chschan

@chschan chschan commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary

RS-22478 added theSrc/scripts/sanitizeHtml.js, which sanitises as_html Box content through DOMPurify and strips <link>. That silently broke the documented Font Awesome icon pattern taught in the Displayr help centre (articles 360004283115 and "Adding Icons to Dashboards Using Font Awesome"):

'<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css" ...>'
'<font color="red" style="font-size: 50pt"><i class="fas fa-arrow-down"></i></font>'

The <i class="fas …"> classes survive, but render blank because the CDN stylesheet/webfont that draws the glyphs — loaded by the stripped <link> — never arrives.

This PR restores that pattern without re-opening arbitrary external stylesheets.

Change

Extract <link> tags before DOMPurify (mirroring the existing <style> handling in sanitizeHtml.js) and re-insert only links that are:

  • rel="stylesheet", and
  • over https:, and
  • to an exact-match allowlisted host (use.fontawesome.com).

Each kept link is rebuilt from scratch, preserving only rel/href/integrity/crossorigin — so onload/other attributes can't ride along, and outerHTML escaping prevents attribute-injection breakout. The allowlist is the STYLESHEET_HOST_ALLOWLIST constant (extend by adding hosts).

Why host-scope <link> (and not just re-allow it)

External CSS is a higher-risk vector than <img> (which Displayr already permits from arbitrary hosts per help article 360004368515): a stylesheet can exfiltrate page state via attribute-selector + background: url(...) tricks, whereas an image cannot. So <link> stays scoped to the Font Awesome CDN. integrity (SRI) is preserved, so even the allowlisted host can't serve tampered CSS.

No q/CSP change needed: /Dashboard emits no style-src/font-src/default-src, so the CDN stylesheet + webfont load once the sanitiser lets the <link> through.

Testing

node_modules/.bin/jest theSrc/scripts/sanitizeHtml.jest.test.js30/30 passing:

  • Font Awesome CDN <link> survives with integrity/crossorigin preserved.
  • Rejection guards: non-allowlisted host, look-alike suffix host (use.fontawesome.com.evil.com), non-stylesheet rel, http:, javascript:, onload stripped, case/whitespace normalised.
  • Regression: the documented KPI flex-box and external-image-linking examples still survive intact (no collateral damage to <img>/<style>).

Notes

  • The glyph renders on live dashboards (network permitting). Offline/exported reports would need Font Awesome bundled into the widget — deferred as a separate follow-up, out of scope here.
  • Published reports keep their frozen bundle until re-rendered/recalculated; new calculations pick up the fix.

🤖 Generated with Claude Code

@chschan chschan changed the title RS-22753: Allowlist Font Awesome CDN <link> in Box sanitiser (incl. RS-22478 sanitiser) RS-22753: Allowlist Font Awesome CDN <link> in Box sanitiser Jul 2, 2026
@chschan chschan changed the title RS-22753: Allowlist Font Awesome CDN <link> in Box sanitiser RS-22753: Allowlist Font Awesome CDN link in Box sanitiser Jul 2, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restores support for the documented Font Awesome icon pattern in Box as_html content by allowing a tightly-scoped subset of <link rel="stylesheet"> tags to survive sanitization, without broadly reopening external stylesheet injection.

Changes:

  • Added extraction and reinsertion of allowlisted HTTPS stylesheet <link> tags (exact host match) around the DOMPurify sanitization pass.
  • Rebuilds kept <link> tags from scratch to preserve only rel, href, integrity, and crossorigin.
  • Added Jest coverage for the allowlist behavior (positive case + rejection guards) and regression coverage for previously documented Box HTML/CSS patterns.

Reviewed changes

Copilot reviewed 2 out of 4 changed files in this pull request and generated no comments.

File Description
theSrc/scripts/sanitizeHtml.js Extracts <link> tags before DOMPurify and reinserts only HTTPS stylesheet links to an exact-match host allowlist, rebuilt with a minimal safe attribute set.
theSrc/scripts/sanitizeHtml.jest.test.js Adds tests ensuring Font Awesome CDN links survive with SRI/CORS preserved, and that non-allowlisted/unsafe <link> variants are rejected; includes regression checks for documented Box features.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread theSrc/scripts/sanitizeHtml.js Outdated
Comment thread theSrc/scripts/sanitizeHtml.js Outdated
Comment thread theSrc/scripts/sanitizeHtml.js Outdated
… fail closed)

Addresses PR #54 review (Kevin Huang):
- LINK_TAG now matches '>' only outside quoted attribute values, so a link with
  e.g. title="a > b" is no longer truncated and dropped.
- Strip HTML comments before <link> extraction so a commented-out (inert) link is
  not revived by the raw-text match.
- Wrap extractAllowedStylesheetLink in try/catch (fail closed) so a runtime without
  <template> support drops the one link instead of aborting all sanitisation.

@kevin-huang-displayr kevin-huang-displayr left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@chschan
chschan merged commit 7c5e9cb into master Jul 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants