{"id":"CVE-2026-115635","kind":"vulnerability","aliases":["CVE-2026-115635"],"related":[],"title":"Elixir ash_postgres: skipped upserts can expose another tenant's row","description":"Incorrect Authorization vulnerability in ash-project ash_postgres allows a user to read another tenant's record through a skipped upsert.\n\nWhen Ash.bulk_create/4 or a single create runs as an upsert with return_skipped_upsert?: true and the upsert is skipped (for example because its upsert_condition does not hold), AshPostgres.DataLayer reads the existing row back by the upsert identity in do_bulk_create/3 and upsert/4. That lookup did not apply the resource's attribute multitenancy, so on a resource using strategy :attribute it could match and return the row of another tenant with the same identity values, exposing its fields to the caller.\n\nThis issue affects ash_postgres: from 2.6.22 before 2.15.2.","summary":"When an upsert is skipped with return_skipped_upsert enabled, ash_postgres reads back the existing row without applying attribute multitenancy. A caller can receive another tenant's record with the same identity values and see its fields.","severity":"medium","cvss":6.0,"epss":null,"exploited":false,"exploited_at":null,"products":[],"ecosystems":[],"tags":["ash","ash_postgres","elixir","multitenancy","package","postgres"],"not_affected_if":["default-config","no-attribute-multitenancy"],"how_to_check":"- Check the ash_postgres version in `mix.lock` or `mix deps` output; affected range is `2.6.22` up to but not including `2.15.2`.\n- Look for resources using multitenancy `strategy :attribute` that call `Ash.bulk_create/4` or create with `upsert?: true` and `return_skipped_upsert?: true`.","fix":"- Upgrade `ash_postgres` to `2.15.2` or later.","status":"open","published_at":"2026-10-25T20:16:32+00:00","first_seen_at":"2026-10-25T20:35:47+00:00","triaged_at":"2026-10-25T20:37:44+00:00","updated_at":"2026-10-25T20:37:44+00:00","category":"package","confidence":0.7,"triage":{"at":"2026-10-25T20:37:44Z","model":"claude-haiku-5-5","output":{"fix":"- Upgrade `ash_postgres` to `2.15.2` or later.","reach":"internet","title":"Elixir ash_postgres: skipped upserts can expose another tenant's row","impact":"medium","summary":"When an upsert is skipped with return_skipped_upsert enabled, ash_postgres reads back the existing row without applying attribute multitenancy. A caller can receive another tenant's record with the same identity values and see its fields.","category":"package","nicknames":[],"who_cares":["elixir","ash","ash_postgres","multitenancy","postgres"],"confidence":0.7,"needs_auth":"yes","worst_case":"caller reads another tenant's record fields","analyst_note":"","how_to_check":"- Check the ash_postgres version in `mix.lock` or `mix deps` output; affected range is `2.6.22` up to but not including `2.15.2`.\n- Look for resources using multitenancy `strategy :attribute` that call `Ash.bulk_create/4` or create with `upsert?: true` and `return_skipped_upsert?: true`.","needs_analyst":false,"not_affected_if":["default-config","no-attribute-multitenancy"],"who_is_affected":"Applications using the Ash framework with the AshPostgres data layer on resources that use attribute-based multitenancy, where upserts are run with return_skipped_upsert enabled and an upsert condition can fail. Applications on a version outside 2.6.22 to 2.15.2, or without attribute multitenancy, are not exposed.","user_interaction":"no","needs_special_setup":"yes","severity_if_unknown":"unknown"},"cost_usd":0.000625,"input_tokens":3464,"output_tokens":558,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-115635':14A,17A '-2026':13A,16A '2.15.2':177C '2.6.22':175C 'affect':171C 'allow':72C 'anoth':8A,50B,77C,156C 'appli':43B,135C 'ash':2A,18B,19B,35B,68C,70C,172C 'ash-project':67C 'ash.bulk':86C 'ashpostgres.datalayer':115C 'attribut':44B,139C,147C 'author':64C 'back':38B,120C 'bulk':127C 'caller':47B,168C 'condit':111C 'could':149C 'creat':91C 'create/3':128C 'create/4':87C 'cve':12A,15A 'elixir':1A,21B 'enabl':34B 'exampl':107C 'exist':40B,118C 'expos':7A,163C 'field':62B,165C 'hold':114C 'ident':57B,124C,161C 'incorrect':63C 'issu':170C 'lookup':132C 'match':150C 'multiten':22B,45B,140C 'packag':23B 'postgr':3A,20B,24B,36B,71C,173C 'project':69C 'read':37B,76C,116C 'receiv':49B 'record':53B,80C 'resourc':137C,144C 'return':31B,97C,152C 'row':11A,41B,119C,154C 'run':92C 'see':60B 'singl':90C 'skip':4A,29B,32B,83C,98C,105C 'strategi':146C 'tenant':9A,51B,78C,157C 'true':100C 'upsert':5A,27B,33B,84C,95C,99C,103C,110C,123C 'upsert/4':130C 'use':145C 'user':74C 'valu':58B,162C 'vulner':65C 'without':42B","nicknames":[],"mitigations":[],"who_affected":"Applications using the Ash framework with the AshPostgres data layer on resources that use attribute-based multitenancy, where upserts are run with return_skipped_upsert enabled and an upsert condition can fail. Applications on a version outside 2.6.22 to 2.15.2, or without attribute multitenancy, are not exposed.","tier":"C","verified":{},"analyst_revisit_at":null,"first_public_at":"2026-10-25T20:16:32+00:00","kev":null,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","cvss_by":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","poc_count":0,"sources":[{"source":"nvd","external_id":"CVE-2026-115635","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-115635","severity":null,"published_at":"2026-10-25T20:16:32+00:00","modified_at":"2026-10-25T20:16:32+00:00","first_seen_at":"2026-10-25T20:35:47+00:00","fetched_at":"2026-10-25T20:35:47+00:00","note":null}],"documents":[],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}