Skip to content

Commit

Permalink
Fix xss vulnerability in the seo component
Browse files Browse the repository at this point in the history
  • Loading branch information
blittle committed Mar 12, 2024
1 parent 5060cf5 commit 720439e
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .changeset/popular-moose-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/hydrogen': patch
---

Fix XSS vulnerability in the SEO component
177 changes: 169 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@
"tempy": "^3.0.0",
"ts-morph": "20.0.0",
"use-resize-observer": "^9.1.0",
"ws": "^8.16.0"
"ws": "^8.16.0",
"sanitize-html": "^2.3.0"
},
"optionalDependencies": {
"@parcel/watcher": "^2.3.0"
Expand Down
6 changes: 5 additions & 1 deletion packages/hydrogen/src/seo/generate-seo-tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type {ComponentPropsWithoutRef} from 'react';
import type {Maybe} from '@shopify/hydrogen-react/storefront-api-types';
import type {Thing, WithContext} from 'schema-dts';

import sanitizeHtml from 'sanitize-html';

const ERROR_PREFIX = 'Error in SEO input: ';

// TODO: Refactor this into more reusable validators or use a library like zod to do this if we decide to use it in
Expand Down Expand Up @@ -503,7 +505,9 @@ export function generateSeoTags<
'script',
{
type: 'application/ld+json',
children: JSON.stringify(block),
children: JSON.stringify(block, (k, value) => {
return typeof value === 'string' ? sanitizeHtml(value) : value;
}),
},
// @ts-expect-error
`json-ld-${block?.['@type'] || block?.name || index++}`,
Expand Down
29 changes: 29 additions & 0 deletions packages/hydrogen/src/seo/seo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,35 @@ describe('seo', () => {
</DocumentFragment>
`);
});

it.only('escapes script content', async () => {
vi.mocked(useMatches).mockReturnValueOnce([
fillMatch({
data: {
seo: {
jsonLd: {
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'Hydrogen Root',
description: '</script><script>alert("hacked")</script>shows up',
},
},
},
}),
]);

const {asFragment} = render(createElement(Seo));

expect(asFragment()).toMatchInlineSnapshot(`
<DocumentFragment>
<script
type="application/ld+json"
>
{"@context":"https://schema.org","@type":"Organization","name":"Hydrogen Root","description":"shows up"}
</script>
</DocumentFragment>
`);
});
});

function fillMatch(partial: Partial<UIMatch<any>> = {}) {
Expand Down

0 comments on commit 720439e

Please sign in to comment.