Skip to content

Commit 9db6877

Browse files
committed
fixes an issue with x-forwarded headers and checkOrigin
1 parent 33e95b9 commit 9db6877

File tree

2 files changed

+36
-40
lines changed

2 files changed

+36
-40
lines changed

.changeset/many-flies-shine.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Enable checkOrigin when astro is behind a reverse proxy

packages/astro/src/core/app/validate-headers.ts

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -85,57 +85,48 @@ export function validateForwardedHeaders(
8585
): { protocol?: string; host?: string; port?: string } {
8686
const result: { protocol?: string; host?: string; port?: string } = {};
8787

88-
// Validate protocol
89-
if (forwardedProtocol) {
90-
if (allowedDomains && allowedDomains.length > 0) {
91-
const hasProtocolPatterns = allowedDomains.some((pattern) => pattern.protocol !== undefined);
92-
if (hasProtocolPatterns) {
93-
// Validate against allowedDomains patterns
94-
try {
95-
const testUrl = new URL(`${forwardedProtocol}://example.com`);
96-
const isAllowed = allowedDomains.some((pattern) => matchPattern(testUrl, pattern));
97-
if (isAllowed) {
98-
result.protocol = forwardedProtocol;
99-
}
100-
} catch {
101-
// Invalid protocol, omit from result
102-
}
103-
} else if (/^https?$/.test(forwardedProtocol)) {
104-
// allowedDomains exist but no protocol patterns, allow http/https
105-
result.protocol = forwardedProtocol;
106-
}
107-
} else if (/^https?$/.test(forwardedProtocol)) {
108-
// No allowedDomains, only allow http/https
109-
result.protocol = forwardedProtocol;
110-
}
88+
// Require allowed domains to validate any forwarded headers - prevents trusting unvalidated headers
89+
if (!allowedDomains || allowedDomains.length === 0) {
90+
return result
11191
}
11292

113-
// Validate port first
114-
if (forwardedPort && allowedDomains && allowedDomains.length > 0) {
115-
const hasPortPatterns = allowedDomains.some((pattern) => pattern.port !== undefined);
116-
if (hasPortPatterns) {
117-
// Validate against allowedDomains patterns
118-
const isAllowed = allowedDomains.some((pattern) => pattern.port === forwardedPort);
119-
if (isAllowed) {
120-
result.port = forwardedPort;
121-
}
122-
}
123-
// If no port patterns, reject the header (strict security default)
124-
}
93+
let allowedDomain: RemotePattern = {}
12594

12695
// Validate host (extract port from hostname for validation)
12796
// Reject empty strings and sanitize to prevent path injection
128-
if (forwardedHost && forwardedHost.length > 0 && allowedDomains && allowedDomains.length > 0) {
129-
const protoForValidation = result.protocol || 'https';
97+
if (forwardedHost && forwardedHost.length > 0) {
13098
const sanitized = sanitizeHost(forwardedHost);
13199
if (sanitized) {
132-
const { hostname, port: portFromHost } = parseHost(sanitized);
133-
const portForValidation = result.port || portFromHost;
134-
if (matchesAllowedDomains(hostname, protoForValidation, portForValidation, allowedDomains)) {
100+
const { hostname } = parseHost(sanitized);
101+
const found = allowedDomains.find((pattern) => pattern.hostname === hostname);
102+
if (found) {
135103
result.host = sanitized;
104+
allowedDomain = found
136105
}
137106
}
138107
}
139108

109+
// If host is not valid, we cannot trust protocol or port from forwarded headers
110+
if (!result.host || !allowedDomain.hostname) {
111+
return result;
112+
}
113+
114+
// Validate port
115+
if (forwardedPort && allowedDomain.port && allowedDomain.port === forwardedPort) {
116+
result.port = forwardedPort;
117+
}
118+
119+
// Validate protocol
120+
if (forwardedProtocol) {
121+
if (allowedDomain.protocol) {
122+
if (allowedDomain.protocol === forwardedProtocol) {
123+
result.protocol = forwardedProtocol;
124+
}
125+
} else if (/^https?$/.test(forwardedProtocol)) {
126+
// allowdDomains does not contain protocol, allow protocol
127+
result.protocol = forwardedProtocol;
128+
}
129+
}
130+
140131
return result;
141132
}

0 commit comments

Comments
 (0)