From 4a30cdb8fe7a34c85522b01b06f0f6b992f3462c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20F=C3=BCrhoff?= <12294151+imagoiq@users.noreply.github.com> Date: Wed, 20 Mar 2024 13:29:55 +0100 Subject: [PATCH] fix(internet-header): Incomplete multi-character sanitization Code Scanning alert on hours field of internet-header footer (#2807) --- .changeset/famous-cameras-kiss.md | 5 +++++ .../internet-header/cypress/e2e/footer.cy.ts | 18 ++++++++++++++++++ .../internet-header/test-configuration.json | 10 ++++++++++ .../post-footer-block-contact.component.tsx | 12 +++++++----- 4 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 .changeset/famous-cameras-kiss.md diff --git a/.changeset/famous-cameras-kiss.md b/.changeset/famous-cameras-kiss.md new file mode 100644 index 0000000000..eb48b02f2a --- /dev/null +++ b/.changeset/famous-cameras-kiss.md @@ -0,0 +1,5 @@ +--- +'@swisspost/internet-header': patch +--- + +Sanitized hours fields in footer against XSS "Incomplete multi-character sanitization" issue. diff --git a/packages/internet-header/cypress/e2e/footer.cy.ts b/packages/internet-header/cypress/e2e/footer.cy.ts index 618159dc41..83afed2159 100644 --- a/packages/internet-header/cypress/e2e/footer.cy.ts +++ b/packages/internet-header/cypress/e2e/footer.cy.ts @@ -54,5 +54,23 @@ describe('footer', () => { }); }); }); + + describe('block-contact', () => { + it('should display pure (without HTML) hours content as it is', () => { + prepare(FOOTER, 'Default'); + cy.get('.block-contact .content-row .text') + .contains('Saturday') + .siblings('.hours') + .should('contain.text', '8am to 12 noon'); + }); + + it('should remove wrapping HTML in hours content when value contains HTML', () => { + prepare(FOOTER, 'Default'); + cy.get('.block-contact .content-row .text') + .contains('Bank holidays') + .siblings('.hours') + .should('contain.text', '8—12'); + }); + }); }); }); diff --git a/packages/internet-header/cypress/fixtures/internet-header/test-configuration.json b/packages/internet-header/cypress/fixtures/internet-header/test-configuration.json index 65e5f7a3f2..ab95befce8 100644 --- a/packages/internet-header/cypress/fixtures/internet-header/test-configuration.json +++ b/packages/internet-header/cypress/fixtures/internet-header/test-configuration.json @@ -3046,6 +3046,16 @@ "text": "Saturday", "title": null }, + { + "address": null, + "describe": null, + "hours": "
8—12
", + "links": null, + "name": "days", + "number": null, + "text": "Bank holidays", + "title": null + }, { "address": null, "describe": null, diff --git a/packages/internet-header/src/components/post-internet-footer/components/post-footer-block-contact.component.tsx b/packages/internet-header/src/components/post-internet-footer/components/post-footer-block-contact.component.tsx index 1dbe1e50eb..988394ec37 100644 --- a/packages/internet-header/src/components/post-internet-footer/components/post-footer-block-contact.component.tsx +++ b/packages/internet-header/src/components/post-internet-footer/components/post-footer-block-contact.component.tsx @@ -1,8 +1,10 @@ import { h } from '@stencil/core'; import { BlockEntity } from '../../../models/footer.model'; -const getContentHours = (hours: string) => hours.replace(/<[^>]*>?/gm, ''); - +function stripHtml(html: string): string { + const doc = new DOMParser().parseFromString(html, 'text/html'); + return doc.body.textContent || ''; +} const callUnblu = () => { if (typeof window['unbluLSLoad'] === 'function') { window['unbluLSLoad'](); @@ -19,7 +21,7 @@ const LiveSupport = (props: { hours: string }) => ( id="liveSupport" type="button" onClick={callUnblu} - innerHTML={getContentHours(props.hours)} + innerHTML={stripHtml(props.hours)} > ); @@ -44,8 +46,8 @@ export const PostFooterBlockContact = (props: { {content.text ?{content.text}
: null} {content.hours && isLiveSupport &&8&emdash;12
and without replace and innerHTML, tags get rendered as text (project="klp" language="en" environment="int02") - + // Some values arrive in the form of8—12
and without replace and innerHTML, tags get rendered as text (project="klp" language="en" environment="int02") + )} {content.describe ?{content.describe}
: null}