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

CVE-2026-82730: Ash TypeScript Auth Bypass Vulnerability

CVE-2026-82730 is an authorization bypass flaw in ash_typescript that exposes denied attribute values through improper handling of field policy markers. This post explains its technical details, affected versions, and mitigation steps.

Published:

CVE-2026-82730 Overview

CVE-2026-82730 is an Incorrect Authorization vulnerability [CWE-863] in the ash-project/ash_typescript library. The flaw allows an unauthorized Remote Procedure Call (RPC) caller to read attribute values that Ash field policies had explicitly denied. When a field policy denies an attribute, Ash substitutes %Ash.ForbiddenField{} while retaining the real value in original_value. The AshTypescript.Rpc.ResultProcessor failed to strip this marker on one code path, causing the denied value to be serialized back to the caller. Affected versions include ash_typescript from 0.11.0 up to but not including 0.18.0.

Critical Impact

An unauthenticated network attacker can retrieve attribute values that field policies were designed to hide, resulting in disclosure of sensitive data inside the very marker structure meant to represent its denial.

Affected Products

  • ash-project/ash_typescript version 0.11.0
  • ash-project/ash_typescript versions up to but not including 0.18.0
  • Applications built on Ash Framework exposing embedded resources via AshTypescript.Rpc

Discovery Timeline

  • 2026-09-01 - CVE-2026-82730 published to NVD
  • 2026-09-01 - Last updated in NVD database

Technical Details for CVE-2026-82730

Vulnerability Analysis

The vulnerability resides in lib/ash_typescript/rpc/result_processor.ex. Ash field policies enforce attribute-level authorization by replacing denied values with an %Ash.ForbiddenField{} struct. That struct retains the actual value in its original_value field because embedded resources must remain writable, and it hides the value from Inspect output rather than removing it.

AshTypescript.Rpc.ResultProcessor strips these markers to nil on its template-driven paths. However, normalize_primitive/1 lacked a matching clause for %Ash.ForbiddenField{}. The marker fell through to the generic struct branch, which called Map.from_struct/1 and serialized every key, including original_value. The denied value was returned inside the marker representing its own denial.

Root Cause

The root cause is a missing pattern-match clause in normalize_primitive/1. The function handled nil and typed values such as DateTime, but had no clause for the authorization sentinel struct %Ash.ForbiddenField{} or the lazy-loading sentinel %Ash.NotLoaded{}. Without explicit redaction, both structs were treated as ordinary maps and fully serialized to JavaScript Object Notation (JSON).

Attack Vector

Exploitation requires only a network-reachable RPC endpoint. The simplest trigger is an action returning an embedded resource as a map, which routes through normalize_resource_struct/2 with an empty template. normalize_value_for_json/1 is a public, unguarded entry point to the same path. An attacker invokes such an action and reads the original_value field from the returned marker to recover the denied attribute value.

text
 def normalize_primitive(nil), do: nil
 
+  # Authorization-redacted and unloaded fields must never be serialized: the
+  # generic struct fallback below would Map.from_struct/1 them and leak
+  # Ash.ForbiddenField.original_value (the real value, hidden only from Inspect).
+  def normalize_primitive(%Ash.ForbiddenField{}), do: nil
+  def normalize_primitive(%Ash.NotLoaded{}), do: nil
+
   def normalize_primitive(value) do
     cond do
       match?(%DateTime{}, value) ->

Source: GitHub commit aa7f9f1. The patch adds explicit clauses that redact %Ash.ForbiddenField{} and %Ash.NotLoaded{} to nil before the generic struct fallback can serialize them.

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 Attacks

Detection Methods for CVE-2026-82730

Indicators of Compromise

  • RPC JSON responses containing objects with the shape { "__struct__": "Elixir.Ash.ForbiddenField", "original_value": ... } or a serialized original_value key.
  • Application logs showing successful RPC calls returning embedded resources to callers whose field policies should have redacted attributes.
  • Unexpected presence of Ash internal struct fields in outbound API payloads.

Detection Strategies

  • Inspect RPC response bodies for the substring original_value and any residual Ash.ForbiddenField or Ash.NotLoaded markers.
  • Add integration tests that assert denied fields resolve to null rather than a struct payload in JSON output.
  • Audit source code for direct calls to AshTypescript.Rpc.ResultProcessor.normalize_value_for_json/1 from custom actions.

Monitoring Recommendations

  • Enable request and response logging on RPC endpoints and alert on responses containing serialized Ash sentinel structs.
  • Track dependency versions in continuous integration and flag any ash_typescript release between 0.11.0 and 0.18.0.
  • Correlate access logs against field-policy authorization decisions to identify unauthorized reads of protected attributes.

How to Mitigate CVE-2026-82730

Immediate Actions Required

  • Upgrade ash_typescript to version 0.18.0 or later across all environments.
  • Rotate or invalidate any secrets previously exposed as embedded-resource attributes if RPC endpoints were reachable by untrusted callers.
  • Review action definitions that return embedded resources as maps and confirm they no longer emit ForbiddenField markers.

Patch Information

The fix is delivered in ash_typescript0.18.0. See the GitHub Security Advisory GHSA-6929-rjmh-4x62, the CNA CVE-2026-82730 record, and the OSV report EEF-CVE-2026-82730. The patch adds normalize_primitive/1 clauses that match %Ash.ForbiddenField{} and %Ash.NotLoaded{} and redact them to nil before the generic struct fallback.

Workarounds

  • Restrict RPC endpoint exposure to trusted networks until the upgrade is deployed.
  • Avoid returning embedded resources as maps from RPC actions where field policies apply.
  • Post-process RPC responses at the transport boundary to strip any keys named original_value from Ash.ForbiddenField or Ash.NotLoaded structs.
bash
# Update the dependency in mix.exs and fetch the patched release
# {:ash_typescript, "~> 0.18.0"}
mix deps.update ash_typescript
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.

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.