Skip to content

Commit

Permalink
feat(embedabble-markdown-html): sanitize html for security
Browse files Browse the repository at this point in the history
  • Loading branch information
TheKnarf committed Jul 10, 2024
1 parent 14f368a commit b21ea02
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 8 deletions.
1 change: 1 addition & 0 deletions packages/embeddable-markdown-html/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"mdast-util-to-hast": "^13.2.0",
"rehype-parse": "^9.0.0",
"rehype-react": "^8.0.0",
"rehype-sanitize": "^6.0.0",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.0",
"unified": "^11.0.5"
Expand Down
2 changes: 2 additions & 0 deletions packages/embeddable-markdown-html/src/html.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { type ReactElement, useEffect, useState } from 'react';
import * as prod from 'react/jsx-runtime';
import rehypeParse, { type Options as RehypeParseOptions } from 'rehype-parse';
import rehypeReact from 'rehype-react';
import rehypeSanitize from 'rehype-sanitize';
import { unified } from 'unified';

// @ts-expect-error: the react types are missing.
Expand All @@ -17,6 +18,7 @@ export const Html: React.FC<{
useEffect(() => {
unified()
.use(rehypeParse, {} as RehypeParseOptions)
.use(rehypeSanitize)
.use(rehypeReact, production)
.process(children)
.then((vfile) => setReactContent(vfile.result as ReactElement))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Html > should render content 1`] = `
<html>
<head />
<body>
<h1>
header
</h1>
</body>
</html>
<h1>
header
</h1>
`;
13 changes: 13 additions & 0 deletions packages/embeddable-markdown-html/tests/html.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,17 @@ describe('Html', () => {

expect(container.firstChild).toMatchSnapshot();
});

test('should not render script tags', async () => {
const { container, getByText } = render(
<Html>{'<div><script>A dangerous script!</script><h1> header </h1></div>'}</Html>,
);

await waitFor(() => {
expect(getByText('header')).toBeInTheDocument();

const scriptTags = container.querySelector('script');
expect(scriptTags).not.toBeInTheDocument();
});
});
});
18 changes: 18 additions & 0 deletions pnpm-lock.yaml

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

0 comments on commit b21ea02

Please sign in to comment.