MCPcopy Create free account
hub / github.com/bytebase/dbhub / validateOrigin

Function validateOrigin

src/utils/cross-origin.ts:182–245  ·  view source on GitHub ↗
(
  originHeader: string | undefined,
  hostHeader: string | undefined,
  allowedHosts: Set<string>
)

Source from the content-addressed store, hash-verified

180 * origin is never echoed back into `Access-Control-Allow-Origin`.
181 */
182export function validateOrigin(
183 originHeader: string | undefined,
184 hostHeader: string | undefined,
185 allowedHosts: Set<string>
186): OriginValidation {
187 const allowAny = allowedHosts.has(ALLOW_ANY_HOST);
188
189 // 1. Validate the Host header (the rebinding defense — runs unconditionally).
190 const trimmedHost = (hostHeader ?? "").trim();
191 if (!trimmedHost || INVALID_HOST_CHARS.test(trimmedHost)) {
192 return { ok: false, status: 400, message: "Malformed Host header" };
193 }
194
195 let hostname: string;
196 try {
197 hostname = new URL(`http://${trimmedHost}`).hostname.toLowerCase();
198 } catch {
199 return { ok: false, status: 400, message: "Malformed Host header" };
200 }
201 if (!hostname) {
202 return { ok: false, status: 400, message: "Malformed Host header" };
203 }
204
205 if (!allowAny && !allowedHosts.has(hostname)) {
206 return {
207 ok: false,
208 status: 403,
209 message:
210 `Host '${hostname}' is not allowed. Only loopback is permitted by default; ` +
211 `set --allowed-hosts (or DBHUB_ALLOWED_HOSTS) to serve other hostnames. ` +
212 `This protects against DNS rebinding.`,
213 };
214 }
215
216 // 2. Origin is only sent by browsers on cross-origin fetches; non-browser
217 // MCP clients omit it. When present it must also be an allowed host so we
218 // never reflect an untrusted origin in the CORS response.
219 if (originHeader === undefined) return { ok: true };
220
221 const trimmedOrigin = originHeader.trim();
222 if (!trimmedOrigin) {
223 return { ok: false, status: 400, message: "Malformed Origin header" };
224 }
225
226 let originHostname: string;
227 try {
228 originHostname = new URL(trimmedOrigin).hostname.toLowerCase();
229 } catch {
230 return { ok: false, status: 400, message: "Malformed Origin header" };
231 }
232 if (!originHostname) {
233 return { ok: false, status: 400, message: "Malformed Origin header" };
234 }
235
236 if (!allowAny && !allowedHosts.has(originHostname)) {
237 return {
238 ok: false,
239 status: 403,

Callers 2

mainFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected