@@ -517,24 +517,37 @@ export async function handleAction({
517
517
// This might be an old browser that doesn't send `host` header. We ignore
518
518
// this case.
519
519
warning = 'Missing `origin` header from a forwarded Server Actions request.'
520
- } else if ( ! host || originDomain !== host . value ) {
520
+ } else if (
521
+ ! host ||
522
+ // ensure that the host header matches the origin header or forwarded host header
523
+ originDomain !== hostHeader ||
524
+ originDomain !== forwardedHostHeader
525
+ ) {
521
526
// If the customer sets a list of allowed origins, we'll allow the request.
522
527
// These are considered safe but might be different from forwarded host set
523
528
// by the infra (i.e. reverse proxies).
524
529
if ( isCsrfOriginAllowed ( originDomain , serverActions ?. allowedOrigins ) ) {
525
530
// Ignore it
526
531
} else {
527
532
if ( host ) {
528
- // This seems to be an CSRF attack. We should not proceed the action.
529
- console . error (
530
- `\`${
531
- host . type
532
- } \` header with value \`${ limitUntrustedHeaderValueForLogs (
533
- host . value
534
- ) } \` does not match \`origin\` header with value \`${ limitUntrustedHeaderValueForLogs (
535
- originDomain
536
- ) } \` from a forwarded Server Actions request. Aborting the action.`
537
- )
533
+ // This seems to be an CSRF attack. We should not proceed the action
534
+ // We have have either the `x-forwarded-host` or `host` header, but neither match the `origin` header.
535
+ if ( hostHeader && originDomain !== hostHeader ) {
536
+ logCSRFError ( {
537
+ originDomain,
538
+ headerType : HostType . Host ,
539
+ headerValue : hostHeader ,
540
+ } )
541
+ } else if (
542
+ forwardedHostHeader &&
543
+ originDomain !== forwardedHostHeader
544
+ ) {
545
+ logCSRFError ( {
546
+ originDomain,
547
+ headerType : HostType . XForwardedHost ,
548
+ headerValue : forwardedHostHeader ,
549
+ } )
550
+ }
538
551
} else {
539
552
// This is an attack. We should not proceed the action.
540
553
console . error (
@@ -1065,3 +1078,21 @@ function getActionModIdOrError(
1065
1078
)
1066
1079
}
1067
1080
}
1081
+
1082
+ function logCSRFError ( {
1083
+ originDomain,
1084
+ headerType,
1085
+ headerValue,
1086
+ } : {
1087
+ originDomain : string
1088
+ headerType : HostType
1089
+ headerValue : string
1090
+ } ) {
1091
+ console . error (
1092
+ `\`${ headerType } \` header with value \`${ limitUntrustedHeaderValueForLogs (
1093
+ headerValue
1094
+ ) } \` does not match \`origin\` header with value \`${ limitUntrustedHeaderValueForLogs (
1095
+ originDomain
1096
+ ) } \` from a forwarded Server Actions request. Aborting the action.`
1097
+ )
1098
+ }
0 commit comments