CVE-2026-81643 Overview
CVE-2026-81643 is an Incorrect Authorization vulnerability [CWE-863] in the ash-project/ash_graphql library. The flaw exists in AshGraphql.Subscription.Batcher, where the authorization-suppression filter should_send?/1 is applied only to the first notification in a batch. Remaining notifications bypass the filter and reach pubsub.publish_subscription/2, exposing records the subscriber is not authorized to view. Affected versions span 1.4.0 through versions before 1.11.0. The issue was disclosed via GitHub Security Advisory GHSA-j684-hch4-q888 and patched in commit e8e67f39.
Critical Impact
Authenticated GraphQL subscribers can receive payloads for records they are not authorized to see when two or more qualifying notifications arrive within the default one-second batch interval.
Affected Products
- ash_graphql versions 1.4.0 through versions before 1.11.0
- Elixir applications using AshGraphql subscriptions with default batching enabled
- GraphQL APIs relying on AshGraphql.Subscription.Batcher for authorization filtering
Discovery Timeline
- 2026-08-30 - CVE-2026-81643 published to NVD
- 2026-09-01 - Last updated in NVD database
Technical Details for CVE-2026-81643
Vulnerability Analysis
The vulnerability resides in the subscription batching path of AshGraphql.Subscription.Batcher. The do_send/5 function resolves the first notification of a batch and passes it through should_send?/1. That filter drops results whose errors are coded forbidden or not_found, or which carry no code, preventing unauthorized data from reaching subscribers.
The remaining notifications in the batch are read from the process dictionary, re-run through the Absinthe pipeline, and appended to the outgoing results. This second code path never invokes should_send?/1. The downstream not is_nil(record) guard in pubsub.publish_subscription/2 only drops nil records, not error-carrying results. Any two qualifying notifications arriving within the default one-second batch interval trigger the leak, and batching is the default path.
Root Cause
The root cause is an incomplete authorization check [CWE-863] in batch processing. The suppression filter that removes forbidden and not_found results was applied inconsistently: to the first notification only, not to the entire batch. Error-carrying results therefore propagated to subscribers who lacked authorization for the underlying records.
Attack Vector
An authenticated subscriber with low privileges opens a GraphQL subscription. When another user's action produces notifications on the same subscription topic within the one-second batch window, the additional notifications skip authorization filtering. The subscriber receives payloads for records outside their authorization scope. No user interaction from the victim is required.
batch ->
batch =
- Enum.map(batch, fn item ->
+ batch
+ |> Enum.map(fn item ->
pipeline =
Absinthe.Subscription.Local.pipeline(doc, {:pre_resolved, item})
{:ok, %{result: data}, _} = Absinthe.Pipeline.run(doc.source, pipeline)
data
end)
+ # Apply the same authorization-suppression filter as first_results, or
+ # forbidden/not_found results in the batch leak to the subscriber.
+ |> Enum.filter(&should_send?/1)
[batch] ++ first_results
end
Source: GitHub Commit e8e67f39. The patch pipes the batch through Enum.filter(&should_send?/1) so the authorization-suppression filter applies to every result, not just the first.
Detect Identity Attacks the Moment Authentication Fails
Singularity™ Identity surfaces credential misuse, lateral movement, and privilege escalation in real time, so you can contain the breach before it spreads.
Stop Identity AttacksDetection Methods for CVE-2026-81643
Indicators of Compromise
- GraphQL subscription responses containing records the authenticated principal should not have access to based on the application's authorization policy.
- Application logs showing forbidden or not_found Ash errors immediately preceding successful subscription payload deliveries to the same client.
- Concurrent write activity from multiple users producing subscription notifications within the one-second batch window on the affected topic.
Detection Strategies
- Inventory Elixir dependency manifests (mix.lock, mix.exs) across services for ash_graphql versions between 1.4.0 and versions prior to 1.11.0.
- Add server-side assertions in subscription resolvers that log any result whose Ash error code is forbidden or not_found prior to serialization.
- Compare subscriber identity against the actor authorized to view each emitted record in staging environments to surface leakage during load tests.
Monitoring Recommendations
- Enable audit logging on GraphQL subscription publish events, capturing subscriber identity, record identifier, and authorization result.
- Alert on subscription payload volumes that exceed the number of records a subscriber's policy permits over a rolling window.
- Retain subscription telemetry for correlation with downstream data-access anomalies and post-incident review.
How to Mitigate CVE-2026-81643
Immediate Actions Required
- Upgrade ash_graphql to version 1.11.0 or later across all Elixir services using AshGraphql subscriptions.
- Audit recent subscription telemetry for evidence of unauthorized payload delivery to authenticated subscribers.
- Rotate or invalidate any sensitive data that may have been disclosed to unauthorized subscribers.
Patch Information
The fix is delivered in ash_graphql1.11.0 via commit e8e67f39. The patch applies should_send?/1 to the entire batch in AshGraphql.Subscription.Batcher, ensuring forbidden and not_found results are suppressed before reaching pubsub.publish_subscription/2. See the GitHub Security Advisory GHSA-j684-hch4-q888 and the OSV entry EEF-CVE-2026-81643 for advisory metadata.
Workarounds
- If upgrade is not immediately possible, disable subscription batching or configure a batch interval that prevents co-batching of notifications for different actors.
- Introduce an application-level filter around pubsub.publish_subscription/2 that drops results carrying Ash error codes forbidden or not_found.
- Restrict subscription topics so that notifications targeting distinct authorization scopes cannot land in the same batch.
# Update ash_graphql in mix.exs and refresh the lockfile
# {:ash_graphql, "~> 1.11.0"}
mix deps.update ash_graphql
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.

