CVE-2026-82746 Overview
CVE-2026-82746 is a missing authorization vulnerability [CWE-862] in the ash-project/ash Elixir framework. The flaw exists in Ash.update_many/4, which executes as a single atomic data-layer statement, such as a SQL MERGE, when an atomic strategy is used. The Ash.Actions.Update.UpdateMany module in lib/ash/actions/update/update_many.ex took this atomic path even when authorize?: true was set, without applying resource policies. An actor could update rows forbidden by policy, including records belonging to other actors or tenants. The issue affects ash versions from 3.29.0 before 3.32.2.
Critical Impact
Authenticated actors can bypass resource policy filters and modify records they are not authorized to update, including cross-tenant data.
Affected Products
- ash-project/ash Elixir library, versions >= 3.29.0
- ash-project/ash Elixir library, versions < 3.32.2
- Applications using Ash.update_many/4 on data layers that support update_many (for example, SQL backends supporting MERGE)
Discovery Timeline
- 2026-09-01 - CVE-2026-82746 published to NVD
- 2026-09-01 - Last updated in NVD database
Technical Details for CVE-2026-82746
Vulnerability Analysis
The vulnerability sits in the Ash framework's bulk update execution path. Ash.update_many/4 supports both an atomic path, which pushes a single statement to the data layer, and a per-record path, which iterates changesets. The atomic path is preferred when the strategy is :atomic or :atomic_batches and the data layer implements update_many.
Under authorize?: true, the atomic branch dispatched the update without merging the resource's policy filter into the statement. The data layer therefore executed the update against every row matching the primary key set, ignoring the row-level restrictions imposed by Ash policies. An actor scoped to their own tenant or record set could thus modify rows outside that scope by targeting known primary keys.
Root Cause
The root cause is missing authorization enforcement on a fast path. The eligibility check for the atomic branch did not require the data layer to support changeset_filter when authorization was requested. Because policy decisions are expressed as filters merged into changesets, skipping that merge on the atomic path allowed policy-forbidden rows to be updated. This is a classic broken access control pattern where an optimization bypasses the guard that the slower path applies.
Attack Vector
An authenticated actor invokes a bulk update action that resolves to Ash.update_many/4 and targets primary keys owned by another actor or tenant. The atomic path executes the write with no policy filter, and the data layer commits the update. Exploitation requires knowledge or enumeration of target primary keys and access to an action that uses the atomic strategy.
# Patch: lib/ash/actions/update/bulk.ex
- defp authorize_atomic_changeset(query, changeset, opts) do
+ @doc false
+ def authorize_atomic_changeset(query, changeset, opts) do
if opts[:authorize?] do
case Ash.can(
changeset,
# Patch: lib/ash/actions/update/update_many.ex
use_update_many? =
Ash.DataLayer.data_layer_can?(resource, :update_many) and
- (:atomic in strategy or :atomic_batches in strategy)
+ (:atomic in strategy or :atomic_batches in strategy) and
+ (!opts[:authorize?] or Ash.DataLayer.data_layer_can?(resource, :changeset_filter))
Source: GitHub commit ed4e656
Detection Methods for CVE-2026-82746
Indicators of Compromise
- Application audit log entries showing successful updates to records where the acting actor's tenant or ownership fields do not match the target row.
- Database write activity via MERGE or bulk UPDATE statements against resources with policies, without a corresponding policy-derived WHERE clause.
- Unexpected modifications to primary-key-addressed rows immediately following calls into Ash.update_many/4 code paths.
Detection Strategies
- Review application logs for invocations of bulk update actions where the resulting affected row count exceeds the actor's authorized scope.
- Add integration tests that call Ash.update_many/4 with authorize?: true and assert that policy-forbidden rows remain unchanged.
- Enable data-layer query logging and compare emitted SQL for atomic bulk updates against the expected policy filter fragment.
Monitoring Recommendations
- Monitor for ash dependency versions between 3.29.0 and 3.32.2 across build manifests (mix.lock) in CI pipelines.
- Alert on schema-level tenant or ownership column changes performed by actors whose session context does not match the modified rows.
How to Mitigate CVE-2026-82746
Immediate Actions Required
- Upgrade ash to version 3.32.2 or later in all Elixir applications that use Ash.update_many/4 under authorization.
- Audit historical writes on resources exposing bulk update actions to identify unauthorized cross-tenant or cross-actor modifications.
- Review custom actions and code paths that invoke Ash.update_many/4 with authorize?: true and confirm the data layer supports changeset_filter.
Patch Information
The fix is delivered in ash 3.32.2. It restricts the atomic path to data layers that support changeset_filter when authorization is enabled, authorizes each changeset, and merges the resulting policy filter into every changeset so the emitted statement only touches authorized rows. See the GitHub Security Advisory GHSA-j7c9-3fw3-jc64, the CNA advisory for CVE-2026-82746, and the OSV entry EEF-CVE-2026-82746.
Workarounds
- Disable the atomic strategy for affected bulk update actions and force the per-record path until the upgrade is applied.
- Constrain bulk update actions with explicit query filters that replicate policy scoping (for example, tenant identifiers) at the caller level.
- Restrict which actors can invoke bulk update actions through application-layer authorization checks that run before Ash.update_many/4 is called.
# Update the ash dependency in mix.exs and refresh the lockfile
# mix.exs
# {:ash, "~> 3.32.2"}
mix deps.update ash
mix deps.get
mix compile --force
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

