Ash AI 1.0.0 fixes six CVEs across prompts, MCP and agent tools
Six ash_ai vulnerabilities show why agent security spans the entire runtime: prompt rendering, record filters, error handling, MCP and tool-loop progress.
- AUTHOR
- Karol Rapacz / CEO Breachroad · OSCP · PNPT
- PUBLISHED
- 31 August 2026
- READING TIME
- 21 min read
- TOPIC
- AI Security
Six vulnerabilities in ash_ai, part of the Elixir and Ash ecosystem, entered NVD today. The most severe, CVE-2026-77956, has a CVSS 4.0 score of 10.0 and can let a remote unauthenticated client execute Elixir code on the server. The remaining issues cover an MCP DNS-rebinding bypass, update or deletion of the wrong record by an agent tool, secret-bearing error disclosure and a loop that repeatedly calls the model without making progress.
All six flaws are fixed in ash_ai 1.0.0. The affected starting version varies: some issues date to 0.1.0, others to 0.6.0 or 0.8.0. Project advisories were published on 30 August, while the NVD records arrived on 31 August in Warsaw time. Today’s development is therefore the complete set becoming available to public vulnerability feeds.
The cluster matters beyond Elixir users. It does not describe one faulty condition. It exposes six trust boundaries common to agentic systems: data becoming executable syntax, a model selecting a database record, a browser reaching local MCP, orchestration with no progress condition, and errors circulating among a tool, the model and the user.
CVE-2026-77956: a function-built prompt became Elixir code
AshAi.Actions.Prompt supported a prompt defined as a function of input and context. The returned value was then passed through EEx.eval_string/2. EEx is a template facility, but its tags contain Elixir expressions. If the function incorporated user-controlled action arguments, the untrusted fragment did not remain text: it was compiled and run on the server before any model request occurred.
This does not make every ash_ai installation automatically exploitable. There must be a reachable prompt action whose dynamic content includes request data. However, the function form was documented, and no further identity is required when the action itself is public. Execution uses the application’s process privileges, so potential impact includes environment secrets, database connections, files visible to the container and network access available to the service.
The fix separates two cases. A statically configured template may still use EEx, while text returned by a runtime function is not interpreted again as template code. That is the appropriate boundary: application code may deliberately construct a string, but runtime data must not receive a hidden second evaluation phase.
CVE-2026-81315: DNS rebinding against a local MCP server
The second flaw involves the MCP server with the default allowed_origins: nil. Origin validation accepted a request when the origin host matched the connection host and the forwarded scheme said HTTPS. Both signals could be shaped by the request: conn.host came from Host, and the scheme came from raw X-Forwarded-Proto without confirming that a trusted proxy supplied it.
In a DNS-rebinding scenario, an attacker’s domain initially resolves to their infrastructure and later to the victim’s local address. The browser preserves the domain origin while connecting to local MCP. A matching Host and a settable X-Forwarded-Proto could satisfy the flawed check. Malicious page JavaScript could then make cross-site requests to MCP using the user’s actor context.
CVE-2026-81315 affects 0.8.0 through the 0.9 line and scores 7.4. Version 1.0.0 trusts localhost origins by default; other origins require an explicit allowlist. Operators should still bind only to required interfaces, ensure proxies overwrite rather than append forwarding headers and avoid exposing unused MCP endpoints.
CVE-2026-82564: an identity value changed the meaning of a filter
Update and destroy tools built an identity filter directly from raw model arguments. The code expected a scalar identifier, but the query layer interpreted a map as a predicate expression. Instead of comparing a field with a literal, the application evaluated a caller-shaped condition. An omitted key could create an IS NULL match.
This matters because a model or a user influencing tool arguments could retarget an operation at a record they never identified. With a bulk operation and a limit of one, an arbitrary matching record could be affected; in some configurations the condition could cover a much broader set. Resource authorisation may reduce impact, but it should not be expected to repair incorrect object selection.
Version 1.0.0 casts each identity value to the field type and rejects non-scalar input. CVE-2026-82564 affects releases from 0.6.0 and scores 7.1. It is a classic data-versus-expression failure: a structure that looks like JSON at the API boundary acquires program semantics after entering a filter DSL.
Two error-disclosure channels
CVE-2026-75760 is in the vectorisation path. When the embedding provider failed, AshAi.Changes.Vectorize placed inspect(error) in a changeset validation error. AshJsonApi and AshGraphql could return it to the caller. A raw HTTP-client error may contain the URL, provider response body, request state and sometimes an Authorization header carrying the provider API key. Oversized or malformed content sent for vectorisation can intentionally reach the failure path.
CVE-2026-82580 finds a related problem in the tool loop. An exception from a callback or lifecycle hook was converted by Exception.message/1 into tool-result content, appended to the conversation, emitted as a stream event and sent back to the model. A user could receive database constraint details, query fragments, adapter names, policy information or validation data. The model added another propagation route: even when a frontend did not render a technical structure directly, the content remained in context and could reappear in natural-language output.
The first issue scores 7.1 and affects versions from 0.1.0; the second scores 5.3 and starts at 0.6.0. The corrected release logs details on the trusted side and returns a generic client message. Logging needs its own control: central logs should redact secrets, restrict access and use a justified retention period.
CVE-2026-82579: a no-progress loop turns model failure into cost
The tool loop classified a model response as tool_calls, then normalised and filtered the calls. A call lacking a valid name or reusing a processed tool_call_id could disappear. When the post-filter list was empty, the implementation appended no message but started another iteration with identical history.
The model therefore received the same context and could produce the same result. With the supported max_iterations: :infinity, the loop had no endpoint; with a finite limit, it consumed the entire budget. The consequence is not only a busy worker. Every turn may mean another paid provider request, a held connection and accumulated latency. Instruction injection through a document or other context can encourage a model to repeat a spent identifier.
Version 1.0.0 treats an empty post-filter list as terminal. Independently of the patch, organisations should impose finite iteration limits, an end-to-end deadline, token and monetary budgets, idempotent tools, and telemetry that identifies a lack of progress.
Who is affected and how to establish exposure
Locate ash_ai in the deployed artefact, not only in a dependency declaration. Establish the exact version, entry points and runtime configuration. Then perform a compact reachability review:
- find
AshAi.Actions.Promptactions using a function and determine whether their result includes user input; - inventory MCP servers, listening interfaces,
allowed_originsand trusted proxies; - list identity-based update and destroy tools alongside resource authorisation policies;
- determine which client fields are vectorised and how API layers render failures;
- review tool callbacks for exceptions that contain internal data;
- confirm an iteration ceiling, total deadline and budget for every agent run.
The urgent action is upgrading to 1.0.0 or a later compatible release. If rollout must wait, disable reachable actions with dynamic EEx, isolate MCP from untrusted networks, set a strict origin allowlist, withdraw data-changing tools and replace detailed client errors with safe messages. These steps reduce exposure; they are not equivalent to installing the patch.
After upgrading, use small controlled regression cases. Prove that EEx tags inside an argument remain text, complex identity values cannot become a filter, an unknown origin is rejected, an exception does not appear in output, and the loop terminates when every call is removed during normalisation. There is no need to reproduce destructive code execution or burn production model capacity.
Detection and response
Review Elixir process telemetry for unusual subprocess creation, file access and system calls correlated with prompt actions. Look for abrupt embedding-provider errors, API output containing header names or HTTP-structure fragments, update or destroy operations without the expected identity, and repeated model calls sharing the same history hash and tool_call_id.
For MCP, useful signals include public origins reaching a local address, unexpected X-Forwarded-Proto outside the proxy and a mismatch between the listening interface and intended service scope. If CVE-2026-77956 may have been exploited, patching is not the end of investigation: rotate secrets visible to the process and examine image and file integrity, process history and outbound connections.
Source facts and Breachroad conclusions
Affected ranges, CVSS scores, technical mechanisms and the fixed release come from the CVE records, project advisories and ash_ai commits. The review order, telemetry model and cost guardrails are Breachroad’s defensive conclusions. The sources do not report confirmed production exploitation of these six flaws. A vulnerable version proves exposure, not compromise.
Primary sources
- Critical RCE advisory — CVE-2026-77956
- MCP DNS-rebinding advisory — CVE-2026-81315
- Vectorisation error advisory — CVE-2026-75760
- Identity-filter advisory — CVE-2026-82564
- Tool-loop advisory — CVE-2026-82579
- Tool-exception disclosure advisory — CVE-2026-82580
- Erlang Ecosystem Foundation CNA: CVE-2026-77956
- NVD: CVE-2026-77956
An agent is not secure merely because the model does not execute code itself. Our secure AI implementation workshops teach teams to design prompt, tool, data and cost boundaries as one system. Where an independent test of realistic abuse paths is required, a controlled AI red team assessment can provide the missing evidence.


