Add origin checks for UI route submissions#14708
Conversation
🦋 Changeset detectedLatest commit: 7b01c8b The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
🤖 Hello there, We just published version Thanks! |
|
🤖 Hello there, We just published version Thanks! |
| ssr: boolean; | ||
| /** | ||
| * The allowed origins for actions / mutations. Does not apply to routes | ||
| * without a component. micromatch glob patterns are supported. |
There was a problem hiding this comment.
This documentation could be better.
The host header includes protocol (https://), but the comparison happens without.
The docs could state that origins should be provided without protocol.
Also, globs wont match if the origin is "null": *, ** and n* doesn't match.
I'm not sure how to allow if the origin header is completely absent.
There was a problem hiding this comment.
We can get the docs updated to be more specific there - how about "The allowed origins (excluding protocol) for actions / mutations on UI routes (i.e., those with a UI component). Micromatch glob patterns are supported."?
We can also look into the glob matching for null - I would think that should be matched by *.
I'm not sure how to allow if the origin header is completely absent.
If the header is absent, this check won't even happen?
There was a problem hiding this comment.
This caught me off-guard today too. Omitting the protocol from the origin feels like it might be a Bad Idea™, and I'm wondering if RR should be fairly strict about this considering it's meant to mitigate a security issue.
|
This config is baked during export default {
allowedActionOrigins:
process.env.NODE_ENV === 'development'
? ['null']
: ['mylogin.staging.com', 'mylogin.prod.com'],
} satisfies Config;It also broke the login of our site (using EntraID with redirect), so it's not a minor change. |
|
This broke our production as well, we deploy our app to 30 domains so we'd need to include all of them here. |
|
Do your applications have external origins posting to UI routes? I think extending the check to support runtime specification is a probably good idea so we will look into a patch update to permit that. |
You could always use a glob? |
Yes I'll just add the complete list for now. If it will be runtime configurable in the future 👍 Our app is behind a k8s/ingress that causes the |
|
We had the same issue in our production environment for the same reason - our app lives behind k8s that cause the origin and the x-forwarded-for to differ. I don't have much extra to add, I just wanted to leave a comment saying that we got this error in our logs: Just in case anyone else googles this issue. FWIW though I would agree that this was not a minor change |
|
This is currently breaking applications deployed on Vercel and Netlify, even when using the wildcard workaround Here is an example of the combinations of headers that can be expected on those platforms (from log data, obfuscated). |
|
Sorry folks - I didn't look close enough at the glob implementation and missed 2 key details:
For now, you can use I'll talk to @jacob-ebey and see if we should just remove that limitation so |
|
@krissrex If you need to set these dynamically at runtime, you can do so on the import "react-router";
import { createRequestHandler } from "@react-router/express";
import express from "express";
import type { ServerBuild } from "react-router";
export const app = express();
async function getBuild() {
let build: ServerBuild = await import("virtual:react-router/server-build");
return {
...build,
allowedActionOrigins: process.env.NODE_ENV === 'development'
? undefined
: ['*.staging.com', '*.prod.com'],
};
}
app.use(createRequestHandler({ build: getBuild })); |
|
Hey folks - just a head sup that I opened #14722 to improve the docs and make |
| let originHeader = headers.get("origin"); | ||
| let originDomain = | ||
| typeof originHeader === "string" && originHeader !== "null" | ||
| ? new URL(originHeader).host |
There was a problem hiding this comment.
Hi, a coworker said he experienced exceptions from cases where Origin was not a valid URL.
I'm not sure what cases this happen in, but it happened.
TypeError with code: ERR_INVALID_URL.
No description provided.