From 226b49e74098ed8ddac64bfe13f93b1a243ae872 Mon Sep 17 00:00:00 2001 From: Josh Faigan Date: Tue, 11 Nov 2025 16:17:54 -0500 Subject: [PATCH] prevent possible CORS vulnerability --- .changeset/frank-lands-hunt.md | 5 +++++ .../cli/utilities/theme-environment/proxy.ts | 9 +++++++++ .../theme-environment/theme-environment.ts | 18 +++++++++++++----- 3 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 .changeset/frank-lands-hunt.md diff --git a/.changeset/frank-lands-hunt.md b/.changeset/frank-lands-hunt.md new file mode 100644 index 00000000000..b4d7f9c2539 --- /dev/null +++ b/.changeset/frank-lands-hunt.md @@ -0,0 +1,5 @@ +--- +'@shopify/theme': patch +--- + +Fix a possible CORS vulnerability where a website could read data from the localhost server diff --git a/packages/theme/src/cli/utilities/theme-environment/proxy.ts b/packages/theme/src/cli/utilities/theme-environment/proxy.ts index edb2da63542..754dffd9a17 100644 --- a/packages/theme/src/cli/utilities/theme-environment/proxy.ts +++ b/packages/theme/src/cli/utilities/theme-environment/proxy.ts @@ -228,6 +228,15 @@ function patchProxiedResponseHeaders(ctx: DevServerContext, rawResponse: Respons response.headers.delete(header) } + // Remove CORS headers from the proxied response. Our CORS middleware + // will set the correct headers based on the allowed origins. + response.headers.delete('access-control-allow-origin') + response.headers.delete('access-control-allow-credentials') + response.headers.delete('access-control-allow-methods') + response.headers.delete('access-control-allow-headers') + response.headers.delete('access-control-expose-headers') + response.headers.delete('access-control-max-age') + // Link header preloads resources from global CDN, proxy it: const linkHeader = response.headers.get('Link') if (linkHeader) response.headers.set('Link', injectCdnProxy(linkHeader, ctx)) diff --git a/packages/theme/src/cli/utilities/theme-environment/theme-environment.ts b/packages/theme/src/cli/utilities/theme-environment/theme-environment.ts index 9c35377cd68..0504aa81d7f 100644 --- a/packages/theme/src/cli/utilities/theme-environment/theme-environment.ts +++ b/packages/theme/src/cli/utilities/theme-environment/theme-environment.ts @@ -98,16 +98,24 @@ interface DevelopmentServerInstance { function createDevelopmentServer(theme: Theme, ctx: DevServerContext, initialWork: Promise) { const app = createApp() + const allowedOrigins = [`http://${ctx.options.host}:${ctx.options.port}`, `https://${ctx.session.storeFqdn}`] app.use( defineLazyEventHandler(async () => { await initialWork return defineEventHandler((event) => { - handleCors(event, { - origin: '*', - methods: '*', - preflight: {statusCode: 204}, - }) + const origin = event.node.req.headers.origin + + // We only set CORS headers if an Origin header is present in the request. + // This prevents wildcard CORS on direct navigation. + if (origin) { + handleCors(event, { + origin: (requestOrigin) => allowedOrigins.includes(requestOrigin), + credentials: true, + methods: ['GET', 'POST', 'HEAD', 'OPTIONS'], + preflight: {statusCode: 204}, + }) + } }) }), )