/** * Brand-token substitution must not reintroduce markup after sanitization * (GHSA-j347). * * buildCachedPayload sanitizes the operator's HTML and THEN calls * applyBrandTokens on the result, which did a plain `String.replace` with no * escaping. The default templates interpolate tokens into text and into quoted * attributes (`{{company_name}} logo`, * `href="mailto:{{support_email}}"`), so a token value could close the * attribute and inject markup into the public origin. * * The writer is settings.edit (super_admin only) and the CSP blocks inline * script, so this is defence-in-depth rather than a live RCE — but the * sanitize-then-substitute ordering is a real bug either way. */ const path = require('path'); const fs = require('fs'); const os = require('os'); process.env.NODE_ENV = 'test'; process.env.TEST_DATABASE_PATH = path.join( fs.mkdtempSync(path.join(os.tmpdir(), 'picpeak-brandtok-')), 'db.sqlite', ); process.env.JWT_SECRET = process.env.JWT_SECRET || 'brandtok-test-secret'; const { _internal } = require('../../src/services/publicSiteService'); // applyBrandTokens / sanitizeBrandUrl are module-private; the service exports // them under _internal for testing (see publicSiteService module.exports). const { applyBrandTokens, sanitizeBrandUrl } = _internal || {}; const maybe = applyBrandTokens ? describe : describe.skip; maybe('applyBrandTokens escaping (GHSA-j347)', () => { it('escapes markup in a text-position token', () => { const out = applyBrandTokens('

{{company_name}}

', { companyName: '', }); expect(out).not.toContain('