CVE-2026-81315 Overview
CVE-2026-81315 is an Origin Validation Error [CWE-346] in the ash-project/ash_ai library affecting the AshAi.Mcp.Server module. The flaw allows a malicious web page to bypass the Model Context Protocol (MCP) server's DNS-rebinding protection and issue cross-site requests to a user's local MCP server using that user's actor identity. The default configuration accepts an origin when uri.host == conn.host and the forwarded scheme is https. Both values are attacker-controlled, defeating the intended origin check. The issue affects ash_ai versions from 0.8.0 before 1.0.0.
Critical Impact
A malicious web page can bypass DNS-rebinding protection and invoke MCP tools with the victim's actor, gaining confidentiality and integrity impact on local MCP-exposed resources.
Affected Products
- ash-project/ash_ai versions >= 0.8.0 and < 1.0.0
- Deployments using AshAi.Mcp.Server with the default allowed_origins: nil
- Any Elixir application exposing an MCP server via ash_ai to browser clients
Discovery Timeline
- 2026-08-31 - CVE-2026-81315 published to NVD
- 2026-09-01 - Last updated in NVD database
Technical Details for CVE-2026-81315
Vulnerability Analysis
The AshAi.Mcp.Server module implements an origin check intended to satisfy the MCP transport's DNS-rebinding protection requirement. In the vulnerable origin_allowed?/3 function, when allowed_origins is nil (the default), the server accepts any origin whose host matches conn.host provided the forwarded scheme is https.
The attacker controls both inputs. The conn.host value derives from the HTTP Host header, and the scheme is read from the raw X-Forwarded-Proto header without verifying that the request arrived through a trusted reverse proxy. A malicious page can force both values to match its own origin, so no real TLS termination or proxy is required for the check to succeed.
Once the origin check passes, browser JavaScript can invoke MCP endpoints as the authenticated user, executing tools and reading data under the victim's actor context.
Root Cause
The underlying defect is treating attacker-influenced request headers as trusted authorization signals. Host and X-Forwarded-Proto are set by the client (or by JavaScript in a rebound page) and must not be used to authorize a cross-origin request without a trusted-proxy allowlist and TLS validation.
Attack Vector
An attacker hosts a malicious page and uses DNS rebinding to point their domain at the victim's loopback interface. After rebinding, the browser sends requests with Origin and Host headers matching the attacker's domain. Page JavaScript sets X-Forwarded-Proto: https, satisfying the flawed check. The local MCP server then processes cross-site requests bound to the victim's actor.
transport's DNS-rebinding protection requirement.
Returns `:ok` when the request carries no `Origin` header (non-browser
- clients), when the origin's host is a localhost value, when the origin
- matches the request host over HTTPS, or when it is explicitly allowed by
- the `:allowed_origins` option (a list of origin strings, or a 1-arity
- predicate function). Returns `:forbidden` otherwise — respond with HTTP
- 403.
+ clients), when the origin's host is a localhost value, or when it is
+ explicitly allowed by the `:allowed_origins` option (a list of origin
+ strings, or a 1-arity predicate function). Deployments serving a browser
+ client from a non-localhost origin must set `:allowed_origins`; the request
+ `Host` and `X-Forwarded-Proto` headers are attacker-controlled and are not
+ used to authorize an origin. Returns `:forbidden` otherwise — respond with
+ HTTP 403.
"""
def check_origin(conn, opts) do
case Plug.Conn.get_req_header(conn, "origin") do
Source: GitHub Commit 28af68d
Detection Methods for CVE-2026-81315
Indicators of Compromise
- Inbound MCP requests to 127.0.0.1 or a loopback service where the Origin header does not match a localhost value.
- HTTP requests carrying an X-Forwarded-Proto: https header without a corresponding upstream proxy in the deployment topology.
- Rapid DNS resolution changes for external hostnames that resolve to 127.0.0.1 or RFC1918 space (classic DNS rebinding pattern).
Detection Strategies
- Inspect MCP server access logs for Origin values outside the localhost set and for mismatches between Host and expected server hostnames.
- Deploy a browser or DNS-layer control that blocks external DNS responses pointing to internal or loopback addresses.
- Audit ash_ai dependency versions across Elixir services to identify any release in the vulnerable range >= 0.8.0, < 1.0.0.
Monitoring Recommendations
- Enable structured logging of Origin, Host, X-Forwarded-For, and X-Forwarded-Proto headers on all MCP endpoints.
- Alert on any MCP tool invocation that carries an Origin header from an unexpected domain.
- Track actor-bound MCP calls that originate from non-localhost sources so unusual cross-site tool use can be reviewed.
How to Mitigate CVE-2026-81315
Immediate Actions Required
- Upgrade ash_ai to version 1.0.0 or later, which restricts default trust to localhost origins.
- For deployments serving browser clients from non-localhost origins, explicitly configure :allowed_origins with a strict allowlist.
- Remove any reliance on X-Forwarded-Proto or Host headers for authorization decisions in application code.
Patch Information
The fix landed in commit 28af68d73134df0b8fb3aa6ab03e8fd795b07c21. The patched check_origin implementation trusts only localhost origins by default and requires explicit :allowed_origins configuration for any other origin. Attacker-controlled Host and X-Forwarded-Proto headers are no longer consulted for origin authorization. See the GitHub Security Advisory GHSA-c92r-f3rr-q49h and the CNA advisory for full details.
Workarounds
- Bind the MCP server only to 127.0.0.1 and block external interfaces at the host firewall until the upgrade completes.
- Configure a trusted reverse proxy that strips inbound X-Forwarded-Proto and X-Forwarded-Host headers from untrusted clients.
- Use a browser extension or endpoint DNS filter that prevents public hostnames from resolving to loopback or private addresses.
# Elixir/Mix: update ash_ai to the patched release
# mix.exs
# {:ash_ai, "~> 1.0"}
mix deps.update ash_ai
mix deps.get
# Application config: require an explicit origin allowlist for browser clients
# config/runtime.exs
config :my_app, AshAi.Mcp.Server,
allowed_origins: ["https://mcp.example.internal"]
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

