The Origin check of the MCP transport, against DNS rebinding.
A request without an Origin header (every client that is not a browser)
passes. A request with one must name a host this install knows, else it is
answered 403 origin_not_allowed before any key is looked at (the MCP plug
runs this as the :before_auth hook of PhoenixKit.API.Auth).
What is allowed
- the install's canonical host: the host of the
site_urlsetting, else of the endpoint's URL (the same source asPhoenixKit.Utils.Routes.base_url/0, read through the settings cache because this check runs before any rate limit); - when the host app configures
config :phoenix_kit, :api_request_context, {Module, :function}, the:hoststhat function explicitly returns (every domain of a multi-domain install). A hook that returns no:hostskey (a hook that sets only language and currency), an empty or non-string list, junk, or that raises or throws contributes nothing. The hook is called with the conn, and it runs again later in the same request when the request context is resolved, so it must be cheap and free of side effects; - the entries of the
api_mcp_allowed_originssetting, which are full origins:https://client.examplematches scheme, host and port. An entry without://never matches (the Settings page stores only full origins).
The request's own Host header is deliberately not on the list. A
DNS-rebinding page sends Host: evil.test and Origin: http://evil.test;
both come from the attacker, so a list built from the Host header would
admit it. The default PhoenixKit.API.RequestContext host list is exactly
that header, and RequestContext.resolve/1 keeps it whenever a hook returns
no :hosts or fails, which is why this module does not use resolve/1 and
calls the hook itself.
An origin with userinfo, a path, a query, a fragment, a scheme other than
http or https, no host (null, file://), surrounding whitespace or
bytes that are not valid UTF-8 is never allowed. A request with two Origin
headers is refused.
Summary
Functions
Whether origin (the value of an Origin header) is allowed, given the
hosts this install serves and the configured entries of
api_mcp_allowed_origins.
Passes conn when it has no Origin header or an allowed one; otherwise
sends 403 origin_not_allowed and halts.
Functions
Whether origin (the value of an Origin header) is allowed, given the
hosts this install serves and the configured entries of
api_mcp_allowed_origins.
@spec check(Plug.Conn.t()) :: Plug.Conn.t()
Passes conn when it has no Origin header or an allowed one; otherwise
sends 403 origin_not_allowed and halts.