Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-86338

CVE-2026-86338: Ash Framework Information Disclosure Vulnerability

CVE-2026-86338 is an information disclosure flaw in Ash Framework that allows unauthorized access to protected field data through filter-based attacks. This post explains its impact, affected versions, and mitigation steps.

Published:

CVE-2026-86338 Overview

CVE-2026-86338 is an information disclosure vulnerability in the Ash Framework for Elixir. Ash field_policies are designed to prevent filter-based oracle attacks by replacing protected field references in filters with expressions that evaluate to nil. This nilling protection was applied to attributes but not to calculations or aggregates. An authenticated actor whose field policies forbid access to a calculation or aggregate can still reference it in a filter and learn its value by observing which rows match. The flaw affects Ash from version 2.11.0-rc.0 before 3.33.4.

Critical Impact

Lower-privileged actors can extract field-policy-protected calculation and aggregate values one probe at a time through filter APIs commonly exposed via AshGraphql and AshJsonApi.

Affected Products

  • Ash Framework (Elixir) versions 2.11.0-rc.0 through 3.33.3
  • AshGraphql filter interfaces exposing calculations or aggregates
  • AshJsonApi filter interfaces exposing calculations or aggregates

Discovery Timeline

  • 2026-09-16 - CVE-2026-86338 published to NVD
  • 2026-09-16 - Last updated in NVD database

Technical Details for CVE-2026-86338

Vulnerability Analysis

The vulnerability is a broken access control issue [CWE-1220] in the Ash policy authorizer's reference replacement logic. Ash field_policies protect against filter-based information disclosure by rewriting filter references to fields the actor cannot read. The authorizer replaces those references with expressions that always evaluate to nil, neutralizing filters as yes/no oracles.

The replacement logic in lib/ash/policy/authorizer/authorizer.ex only matched Ash.Resource.* structs, such as Ash.Resource.Attribute, Ash.Resource.Aggregate, and Ash.Resource.Calculation. User-supplied filter references to calculations and aggregates arrive as Ash.Query.Calculation and Ash.Query.Aggregate structs. These runtime query structs bypassed the guard clause and ran against real values.

An actor can craft filters such as filter(secret_calc == "x") or filter(comment_count == n) and infer the protected value from whether rows match. This is a classic filter oracle that recovers field-policy-protected values one probe at a time.

Root Cause

The do_replace_ref/2 function in the policy authorizer performed struct-type matching limited to schema-level structs. Query-level reference structs generated during filter parsing were not handled, so field-policy nilling never applied to calculations or aggregates referenced through filter arguments.

Attack Vector

Exploitation requires an authenticated actor with the ability to submit filter arguments to any Ash-backed API. Filtering is commonly exposed to lower-privileged users through AshGraphql and AshJsonApi query arguments. The attacker iteratively submits filters comparing the protected calculation or aggregate to guessed values and reads the answer from the result set size.

text
// Patch: lib/ash/policy/authorizer/authorizer.ex
// Route Ash.Query.Calculation and Ash.Query.Aggregate references
// through the same field-policy nilling as attributes.

        attribute: %struct{name: name},
        relationship_path: relationship_path
      } = ref,
-     %{stack: [{parent, _path, action, domain} | _]} = acc
+     acc
    )
    when struct in [Ash.Resource.Attribute, Ash.Resource.Aggregate, Ash.Resource.Calculation] do
+   replace_named_ref(name, relationship_path, ref, acc)
+ end
+
+ defp do_replace_ref(
+       %{
+         attribute: %Ash.Query.Calculation{calc_name: name},
+         relationship_path: relationship_path
+       } = ref,
+       acc
+     )
+     when is_atom(name) and not is_nil(name) do
+   replace_named_ref(name, relationship_path, ref, acc)
+ end
+
+ defp do_replace_ref(
+       %{
+         attribute: %Ash.Query.Aggregate{agg_name: name},
+         relationship_path: relationship_path
+       } = ref,
+       acc
+     )
+     when is_atom(name) and not is_nil(name) do
+   replace_named_ref(name, relationship_path, ref, acc)

Source: GitHub Commit b3d4503241f3

Detection Methods for CVE-2026-86338

Indicators of Compromise

  • High-volume repeated filter queries from a single actor that vary only one predicate value against the same calculation or aggregate field.
  • Filter arguments referencing calculation or aggregate names that the actor's field policies forbid reading directly.
  • GraphQL or JSON:API requests where response row counts change monotonically as an attacker sweeps a value range.

Detection Strategies

  • Audit application logs for filter expressions that reference calculation or aggregate names restricted by field_policies.
  • Add server-side telemetry that records the resource, action, actor, and filter tree for every Ash query and flag repeated equality probes against sensitive fields.
  • Correlate low-privilege actor identities against unusually high query volume with narrow result sets, a signature of oracle enumeration.

Monitoring Recommendations

  • Enable Ash query tracing in production and forward events to a centralized log store for retention and analysis.
  • Alert on any query where a protected calculation or aggregate appears in a filter predicate before the patch is applied.
  • Track per-actor rates of failed or empty-result filter queries to detect probing behavior.

How to Mitigate CVE-2026-86338

Immediate Actions Required

  • Upgrade Ash to version 3.33.4 or later, which routes calculation and aggregate filter references through the same field-policy nilling as attributes.
  • Inventory resources using field_policies and identify calculations or aggregates exposed to lower-privileged actors via AshGraphql or AshJsonApi filter arguments.
  • Review recent query logs for evidence of filter oracle probing against protected fields.

Patch Information

The fix is delivered in Ash 3.33.4. See the GitHub Security Advisory GHSA-7qr8-wrvq-566q and the corrective commit b3d4503241f3. Additional context is available in the CNA advisory detail and the OSV entry.

Workarounds

  • Temporarily mark affected calculations and aggregates as non-filterable using filterable? false until the upgrade is completed.
  • Restrict filter argument exposure in AshGraphql and AshJsonApi to attributes only for actors covered by field_policies.
  • Add authorization checks in the calling API layer that reject filter payloads referencing sensitive calculation or aggregate names.
bash
# Update dependency in mix.exs
{:ash, "~> 3.33.4"}

# Fetch and compile the patched version
mix deps.update ash
mix deps.compile ash

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.