From b14f485d48f76a33966c9d7ea983ed2773fba4ad Mon Sep 17 00:00:00 2001 From: Stephan Cilliers <5469870+stephancill@users.noreply.github.com> Date: Tue, 8 Oct 2024 17:17:43 +0200 Subject: [PATCH 1/2] fix: default frame renderer security improvements --- .changeset/friendly-eyes-applaud.md | 5 +++++ .changeset/giant-jobs-invent.md | 5 +++++ packages/render/src/ui/index.tsx | 18 +++++++++++++++++- packages/render/src/use-fetch-frame.ts | 16 +++++++++++++--- 4 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 .changeset/friendly-eyes-applaud.md create mode 100644 .changeset/giant-jobs-invent.md diff --git a/.changeset/friendly-eyes-applaud.md b/.changeset/friendly-eyes-applaud.md new file mode 100644 index 000000000..d9c8eb22f --- /dev/null +++ b/.changeset/friendly-eyes-applaud.md @@ -0,0 +1,5 @@ +--- +"@frames.js/render": patch +--- + +fix: enforce http(s) protocol on redirect URLs diff --git a/.changeset/giant-jobs-invent.md b/.changeset/giant-jobs-invent.md new file mode 100644 index 000000000..250a71ad5 --- /dev/null +++ b/.changeset/giant-jobs-invent.md @@ -0,0 +1,5 @@ +--- +"@frames.js/render": patch +--- + +fix: don't render data URIs that are SVG or not images diff --git a/packages/render/src/ui/index.tsx b/packages/render/src/ui/index.tsx index 6935b5d0c..c68292112 100644 --- a/packages/render/src/ui/index.tsx +++ b/packages/render/src/ui/index.tsx @@ -130,6 +130,22 @@ function createDefaultComponents>( Image(props, stylingProps) { const aspectRatio = props.aspectRatio.replace(":", "/"); + let sanitizedSrc = + props.status === "frame-loading" ? undefined : props.src; + + // Don't allow data URLs that are not images -- we don't want to allow arbitrary data to be loaded + if ( + sanitizedSrc?.startsWith("data:") && + !sanitizedSrc?.startsWith("data:image") + ) { + sanitizedSrc = ""; + } + + // Don't allow SVG data URLs -- could contain malicious code + if (sanitizedSrc?.startsWith("data:image/svg")) { + sanitizedSrc = ""; + } + return createElement("img", { ...stylingProps, "data-aspect-ratio": aspectRatio, @@ -211,7 +227,7 @@ type FrameUIProps> = Omit< }; export function FrameUI< - TStylingProps extends Record = StylingProps, + TStylingProps extends Record = StylingProps >(props: FrameUIProps): JSX.Element { const defaultComponents = useMemo( () => createDefaultComponents(props.createElement), diff --git a/packages/render/src/use-fetch-frame.ts b/packages/render/src/use-fetch-frame.ts index 1a9af0717..c0dcdd6ba 100644 --- a/packages/render/src/use-fetch-frame.ts +++ b/packages/render/src/use-fetch-frame.ts @@ -95,7 +95,7 @@ function defaultErrorHandler(error: Error): void { export function useFetchFrame< TSignerStorageType = Record, TFrameActionBodyType extends FrameActionBodyPayload = FrameActionBodyPayload, - TFrameContextType extends FrameContext = FarcasterFrameContext, + TFrameContextType extends FrameContext = FarcasterFrameContext >({ stackAPI, stackDispatch, @@ -314,6 +314,16 @@ export function useFetchFrame< // check the URL is valid const locationUrl = new URL(location); + // Reject non-http(s) URLs + if ( + locationUrl.protocol !== "http:" && + locationUrl.protocol !== "https:" + ) { + throw new Error( + `Redirect location ${location} is not a valid HTTP or HTTPS URL.` + ); + } + onRedirect(locationUrl); stackAPI.markAsDoneWithRedirect({ @@ -959,7 +969,7 @@ function getResponseBody(response: Response): Promise { type SignAndGetFrameActionPayloadOptions< TSignerStorageType, TFrameActionBodyType extends FrameActionBodyPayload, - TFrameContextType extends FrameContext, + TFrameContextType extends FrameContext > = { signerStateActionContext: SignerStateActionContext< TSignerStorageType, @@ -977,7 +987,7 @@ type SignAndGetFrameActionPayloadOptions< async function signAndGetFrameActionBodyPayload< TSignerStorageType, TFrameActionBodyType extends FrameActionBodyPayload, - TFrameContextType extends FrameContext, + TFrameContextType extends FrameContext >({ signerStateActionContext, signFrameAction, From 9acca38291b3beb92a2d6a0c2d58fd0dc4fcb297 Mon Sep 17 00:00:00 2001 From: Stephan Cilliers <5469870+stephancill@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:18:40 +0200 Subject: [PATCH 2/2] fix: pr comments --- packages/render/src/ui/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/render/src/ui/index.tsx b/packages/render/src/ui/index.tsx index c68292112..4a96c9cf2 100644 --- a/packages/render/src/ui/index.tsx +++ b/packages/render/src/ui/index.tsx @@ -138,12 +138,12 @@ function createDefaultComponents>( sanitizedSrc?.startsWith("data:") && !sanitizedSrc?.startsWith("data:image") ) { - sanitizedSrc = ""; + sanitizedSrc = undefined; } // Don't allow SVG data URLs -- could contain malicious code if (sanitizedSrc?.startsWith("data:image/svg")) { - sanitizedSrc = ""; + sanitizedSrc = undefined; } return createElement("img", { @@ -155,7 +155,7 @@ function createDefaultComponents>( }, onLoad: props.onImageLoadEnd, onError: props.onImageLoadEnd, - src: props.status === "frame-loading" ? undefined : props.src, + src: sanitizedSrc, alt: "Frame", }); },