diff --git a/__tests__/ssr.test.tsx b/__tests__/ssr.test.tsx
index 54c0447..c8fe6a0 100644
--- a/__tests__/ssr.test.tsx
+++ b/__tests__/ssr.test.tsx
@@ -71,6 +71,24 @@ describe('ssr', () => {
]);
});
+ it('should escape meta-content', () => {
+ jest.useFakeTimers();
+ const MyComponent = () => {
+ useMeta({ property: 'fb:admins', content: "''<>&" });
+ useMeta({ property: 'fb:something', content: '""' });
+ return
hi
;
+ };
+
+ render();
+ jest.runAllTimers();
+ const { metas } = toStatic();
+
+ expect(metas).toEqual([
+ { content: '""', property: 'fb:something' },
+ { content: '''<>&', property: 'fb:admins' },
+ ]);
+ });
+
it('should render to string (basic-useHead)', () => {
jest.useFakeTimers();
const MyComponent = () => {
diff --git a/src/dispatcher/index.ts b/src/dispatcher/index.ts
index dc116b9..c83a454 100644
--- a/src/dispatcher/index.ts
+++ b/src/dispatcher/index.ts
@@ -201,6 +201,44 @@ export const createDispatcher = () => {
: // istanbul ignore next
undefined,
toStatic: (): StaticPayload => {
+ const ESCAPED_CHARS = /['"&<>]/;
+
+ function escape(str: string) {
+ if (str.length === 0 || ESCAPED_CHARS.test(str) === false) return str;
+
+ let last = 0,
+ i = 0,
+ out = '',
+ ch = '';
+
+ for (; i < str.length; i++) {
+ switch (str.charCodeAt(i)) {
+ case 34:
+ ch = '"';
+ break;
+ case 38:
+ ch = '&';
+ break;
+ case 39:
+ ch = ''';
+ break;
+ case 60:
+ ch = '<';
+ break;
+ case 62:
+ ch = '>';
+ break;
+ default:
+ continue;
+ }
+
+ if (i !== last) out += str.slice(last, i);
+ out += ch;
+ last = i + 1;
+ }
+ if (i !== last) out += str.slice(last, i);
+ return out;
+ }
// Will process the two arrays, taking the first title in the array and returning {string}
// Then do a similar for the meta's. (will also need to add links, and add a linkQueue). Note that both queues
// will need a reset to prevent memory leaks.
@@ -240,7 +278,7 @@ export const createDispatcher = () => {
}
: {
[meta.keyword]: meta[meta.keyword],
- content: meta.content,
+ content: escape(meta.content),
}
),
};