Skip to content

Commit

Permalink
Merge pull request from GHSA-qhjf-hm5j-335w
Browse files Browse the repository at this point in the history
* escape html characters in JSON string before injecting it into stream

* Add changeset

---------

Co-authored-by: Lenz Weber-Tronic <lorenz.weber-tronic@apollographql.com>
Co-authored-by: Phil Pluckthun <phil@kitten.sh>
  • Loading branch information
3 people authored Jan 30, 2024
1 parent b4c46f2 commit 4b7011b
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/brave-buses-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@urql/next': patch
---

Fix `CVE-2024-24556`, addressing an XSS vulnerability, where `@urql/next` failed to escape HTML characters in JSON payloads injected into RSC hydration bodies. When an attacker is able to manipulate strings in the JSON response in RSC payloads, this could cause HTML to be evaluated via a typical XSS vulnerability (See [`GHSA-qhjf-hm5j-335w`](https://github.com/urql-graphql/urql/security/advisories/GHSA-qhjf-hm5j-335w) for details.)
3 changes: 2 additions & 1 deletion packages/next-urql/src/DataHydrationContext.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import { ServerInsertedHTMLContext } from 'next/navigation';
import type { UrqlResult } from './useUrqlValue';
import { htmlEscapeJsonString } from './htmlescape';

interface DataHydrationValue {
isInjecting: boolean;
Expand All @@ -19,7 +20,7 @@ const DataHydrationContext = React.createContext<

function transportDataToJS(data: any) {
const key = 'urql_transport';
return `(window[Symbol.for("${key}")] ??= []).push(${JSON.stringify(data)})`;
return `(window[Symbol.for("${key}")] ??= []).push(${htmlEscapeJsonString(JSON.stringify(data))})`;
}

export const DataHydrationContextProvider = ({
Expand Down
24 changes: 24 additions & 0 deletions packages/next-urql/src/htmlescape.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// --------------------------------------------------------------------------------
//
// copied from
// https://github.com/vercel/next.js/blob/6bc07792a4462a4bf921a72ab30dc4ab2c4e1bda/packages/next/src/server/htmlescape.ts
// License: https://github.com/vercel/next.js/blob/6bc07792a4462a4bf921a72ab30dc4ab2c4e1bda/packages/next/license.md
//
// --------------------------------------------------------------------------------

// This utility is based on https://github.com/zertosh/htmlescape
// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE

const ESCAPE_LOOKUP: { [match: string]: string } = {
"&": "\\u0026",
">": "\\u003e",
"<": "\\u003c",
"\u2028": "\\u2028",
"\u2029": "\\u2029",
};

export const ESCAPE_REGEX = /[&><\u2028\u2029]/g;

export function htmlEscapeJsonString(str: string): string {
return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
}

0 comments on commit 4b7011b

Please sign in to comment.