{"api_version":"1","generated_at":"2026-09-11T16:44:38+00:00","cve":"CVE-2026-81318","urls":{"html":"https://cve.report/CVE-2026-81318","api":"https://cve.report/api/cve/CVE-2026-81318.json","docs":"https://cve.report/api","cve_org":"https://www.cve.org/CVERecord?id=CVE-2026-81318","nvd":"https://nvd.nist.gov/vuln/detail/CVE-2026-81318"},"summary":{"title":"Distinct-query aggregate drops the tenant schema prefix, leaking across tenants in AshSql","description":"Incorrect Authorization vulnerability in ash-project ash_sql allows a caller in a schema-based multitenant application to receive aggregate values computed from another tenant's rows.\n\nWhen an aggregate is computed over a distinct query, AshSql.AggregateQuery.add_single_aggs/5 rebuilds the outer query from query.from.source alone, which is only the {table, schema} tuple and does not carry query.prefix or query.from.prefix. For strategy(:context) multitenancy those hold the tenant schema, so the rebuilt outer query reads the repo's default schema while the inner correlated subquery still reads the tenant schema, and the two are joined only on primary key. The aggregate, and any relationship join added off the prefix-less binding, is then computed against the wrong tenant's rows. The neighbouring limit and exists branches instead wrap the query with subquery/1, which preserves the prefix.\n\nThis issue affects ash_sql: from 0.1.0 before 0.7.1.","state":"PUBLISHED","assigner":"EEF","published_at":"2026-08-30 12:17:19","updated_at":"2026-09-01 21:15:00"},"problem_types":["CWE-863","CWE-863 CWE-863 Incorrect Authorization"],"metrics":[{"version":"4.0","source":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","type":"Secondary","score":"2.1","severity":"LOW","vector":"CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:L/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","data":{"version":"4.0","vectorString":"CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:L/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","baseScore":2.1,"baseSeverity":"LOW","attackVector":"LOCAL","attackComplexity":"LOW","attackRequirements":"PRESENT","privilegesRequired":"NONE","userInteraction":"NONE","vulnConfidentialityImpact":"LOW","vulnIntegrityImpact":"NONE","vulnAvailabilityImpact":"NONE","subConfidentialityImpact":"NONE","subIntegrityImpact":"NONE","subAvailabilityImpact":"NONE","exploitMaturity":"NOT_DEFINED","confidentialityRequirement":"NOT_DEFINED","integrityRequirement":"NOT_DEFINED","availabilityRequirement":"NOT_DEFINED","modifiedAttackVector":"NOT_DEFINED","modifiedAttackComplexity":"NOT_DEFINED","modifiedAttackRequirements":"NOT_DEFINED","modifiedPrivilegesRequired":"NOT_DEFINED","modifiedUserInteraction":"NOT_DEFINED","modifiedVulnConfidentialityImpact":"NOT_DEFINED","modifiedVulnIntegrityImpact":"NOT_DEFINED","modifiedVulnAvailabilityImpact":"NOT_DEFINED","modifiedSubConfidentialityImpact":"NOT_DEFINED","modifiedSubIntegrityImpact":"NOT_DEFINED","modifiedSubAvailabilityImpact":"NOT_DEFINED","Safety":"NOT_DEFINED","Automatable":"NOT_DEFINED","Recovery":"NOT_DEFINED","valueDensity":"NOT_DEFINED","vulnerabilityResponseEffort":"NOT_DEFINED","providerUrgency":"NOT_DEFINED"}},{"version":"4.0","source":"CNA","type":"CVSS","score":"2.1","severity":"LOW","vector":"CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N","data":{"Automatable":"NOT_DEFINED","Recovery":"NOT_DEFINED","Safety":"NOT_DEFINED","attackComplexity":"LOW","attackRequirements":"PRESENT","attackVector":"LOCAL","baseScore":2.1,"baseSeverity":"LOW","privilegesRequired":"NONE","providerUrgency":"NOT_DEFINED","subAvailabilityImpact":"NONE","subConfidentialityImpact":"NONE","subIntegrityImpact":"NONE","userInteraction":"NONE","valueDensity":"NOT_DEFINED","vectorString":"CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N","version":"4.0","vulnAvailabilityImpact":"NONE","vulnConfidentialityImpact":"LOW","vulnIntegrityImpact":"NONE","vulnerabilityResponseEffort":"NOT_DEFINED"}}],"references":[{"url":"https://github.com/ash-project/ash_sql/security/advisories/GHSA-ww8j-58rc-f8h3","name":"https://github.com/ash-project/ash_sql/security/advisories/GHSA-ww8j-58rc-f8h3","refsource":"134c704f-9b21-4f2e-91b3-4a467353bcc0","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://osv.dev/vulnerability/EEF-CVE-2026-81318","name":"https://osv.dev/vulnerability/EEF-CVE-2026-81318","refsource":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://cna.erlef.org/cves/CVE-2026-81318.html","name":"https://cna.erlef.org/cves/CVE-2026-81318.html","refsource":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://github.com/ash-project/ash_sql/commit/3d95478cc9e1d5bfaf6144fe9b9793f29e5ab889","name":"https://github.com/ash-project/ash_sql/commit/3d95478cc9e1d5bfaf6144fe9b9793f29e5ab889","refsource":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-81318","name":"CVE Program record","refsource":"CVE.ORG","tags":["canonical"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-81318","name":"NVD vulnerability detail","refsource":"NVD","tags":["canonical","analysis"]}],"affected":[{"source":"CNA","vendor":"ash-project","product":"ash_sql","version":"affected 0.1.0 0.7.1 semver","platforms":[]},{"source":"CNA","vendor":"ash-project","product":"ash_sql","version":"affected dd092ed273dec7bd2194352f24a39229fc8ae68b 3d95478cc9e1d5bfaf6144fe9b9793f29e5ab889 git","platforms":[]}],"timeline":[],"solutions":[],"workarounds":[],"exploits":[],"credits":[{"source":"CNA","value":"Peter Ullrich","lang":"en"},{"source":"CNA","value":"Peter Ullrich","lang":"en"},{"source":"CNA","value":"Zach Daniel / Ash Project","lang":"en"},{"source":"CNA","value":"Jonatan Männchen / EEF","lang":"en"}],"nvd_cpes":[],"vendor_comments":[],"enrichments":{"kev":null,"epss":{"cve_year":"2026","cve_id":"81318","cve":"CVE-2026-81318","epss":"0.001200000","percentile":"0.020110000","score_date":"2026-09-03","updated_at":"2026-09-04 00:08:06"},"legacy_qids":[]},"source_records":{"cve_program":{"containers":{"adp":[{"metrics":[{"other":{"content":{"id":"CVE-2026-81318","options":[{"Exploitation":"poc"},{"Automatable":"no"},{"Technical Impact":"partial"}],"role":"CISA Coordinator","timestamp":"2026-08-31T16:59:17.533248Z","version":"2.0.3"},"type":"ssvc"}}],"providerMetadata":{"dateUpdated":"2026-08-31T16:59:41.443Z","orgId":"134c704f-9b21-4f2e-91b3-4a467353bcc0","shortName":"CISA-ADP"},"references":[{"tags":["exploit"],"url":"https://github.com/ash-project/ash_sql/security/advisories/GHSA-ww8j-58rc-f8h3"}],"title":"CISA ADP Vulnrichment"}],"cna":{"affected":[{"collectionURL":"https://repo.hex.pm","cpes":["cpe:2.3:a:ash-project:ash_sql:*:*:*:*:*:*:*:*"],"defaultStatus":"unaffected","modules":["'Elixir.AshSql.AggregateQuery'"],"packageName":"ash_sql","packageURL":"pkg:hex/ash_sql","product":"ash_sql","programFiles":["lib/aggregate_query.ex"],"programRoutines":[{"name":"'Elixir.AshSql.AggregateQuery':add_single_aggs/5"}],"repo":"https://github.com/ash-project/ash_sql","vendor":"ash-project","versions":[{"lessThan":"0.7.1","status":"affected","version":"0.1.0","versionType":"semver"}]},{"collectionURL":"https://github.com","cpes":["cpe:2.3:a:ash-project:ash_sql:*:*:*:*:*:*:*:*"],"defaultStatus":"unaffected","modules":["'Elixir.AshSql.AggregateQuery'"],"packageName":"ash-project/ash_sql","packageURL":"pkg:github/ash-project/ash_sql","product":"ash_sql","programFiles":["lib/aggregate_query.ex"],"programRoutines":[{"name":"'Elixir.AshSql.AggregateQuery':add_single_aggs/5"}],"repo":"https://github.com/ash-project/ash_sql","vendor":"ash-project","versions":[{"lessThan":"3d95478cc9e1d5bfaf6144fe9b9793f29e5ab889","status":"affected","version":"dd092ed273dec7bd2194352f24a39229fc8ae68b","versionType":"git"}]}],"configurations":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>An application must use AshPostgres schema-based (<code>strategy(:context)</code>) multitenancy and compute an aggregate over a <code>distinct</code> query (for example an aggregate whose query filters across a to-many relationship).</p>"},{"base64":false,"type":"text/markdown","value":"An application must use AshPostgres schema-based (`strategy(:context)`) multitenancy and compute an aggregate over a `distinct` query (for example an aggregate whose query filters across a to-many relationship)."}],"value":"An application must use AshPostgres schema-based (strategy(:context)) multitenancy and compute an aggregate over a distinct query (for example an aggregate whose query filters across a to-many relationship)."}],"cpeApplicability":[{"nodes":[{"cpeMatch":[{"criteria":"cpe:2.3:a:ash-project:ash_sql:*:*:*:*:*:*:*:*","versionEndExcluding":"0.7.1","versionStartIncluding":"0.1.0","vulnerable":true}],"negate":false,"operator":"OR"}],"operator":"AND"}],"credits":[{"lang":"en","type":"finder","value":"Peter Ullrich"},{"lang":"en","type":"reporter","value":"Peter Ullrich"},{"lang":"en","type":"remediation developer","value":"Zach Daniel / Ash Project"},{"lang":"en","type":"coordinator","value":"Jonatan Männchen / EEF"}],"descriptions":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>Incorrect Authorization vulnerability in ash-project ash_sql allows a caller in a schema-based multitenant application to receive aggregate values computed from another tenant's rows.</p>\n<p>When an aggregate is computed over a <code>distinct</code> query, <code>AshSql.AggregateQuery.add_single_aggs/5</code> rebuilds the outer query from <code>query.from.source</code> alone, which is only the <code>{table, schema}</code> tuple and does not carry <code>query.prefix</code> or <code>query.from.prefix</code>. For <code>strategy(:context)</code> multitenancy those hold the tenant schema, so the rebuilt outer query reads the repo's default schema while the inner correlated subquery still reads the tenant schema, and the two are joined only on primary key. The aggregate, and any relationship join added off the prefix-less binding, is then computed against the wrong tenant's rows. The neighbouring limit and exists branches instead wrap the query with <code>subquery/1</code>, which preserves the prefix.</p>\n<p>This issue affects ash_sql: from 0.1.0 before 0.7.1.</p>"},{"base64":false,"type":"text/markdown","value":"Incorrect Authorization vulnerability in ash-project ash_sql allows a caller in a schema-based multitenant application to receive aggregate values computed from another tenant's rows.\n\nWhen an aggregate is computed over a `distinct` query, `AshSql.AggregateQuery.add_single_aggs/5` rebuilds the outer query from `query.from.source` alone, which is only the `{table, schema}` tuple and does not carry `query.prefix` or `query.from.prefix`. For `strategy(:context)` multitenancy those hold the tenant schema, so the rebuilt outer query reads the repo's default schema while the inner correlated subquery still reads the tenant schema, and the two are joined only on primary key. The aggregate, and any relationship join added off the prefix-less binding, is then computed against the wrong tenant's rows. The neighbouring limit and exists branches instead wrap the query with `subquery/1`, which preserves the prefix.\n\nThis issue affects ash_sql: from 0.1.0 before 0.7.1."}],"value":"Incorrect Authorization vulnerability in ash-project ash_sql allows a caller in a schema-based multitenant application to receive aggregate values computed from another tenant's rows.\n\nWhen an aggregate is computed over a distinct query, AshSql.AggregateQuery.add_single_aggs/5 rebuilds the outer query from query.from.source alone, which is only the {table, schema} tuple and does not carry query.prefix or query.from.prefix. For strategy(:context) multitenancy those hold the tenant schema, so the rebuilt outer query reads the repo's default schema while the inner correlated subquery still reads the tenant schema, and the two are joined only on primary key. The aggregate, and any relationship join added off the prefix-less binding, is then computed against the wrong tenant's rows. The neighbouring limit and exists branches instead wrap the query with subquery/1, which preserves the prefix.\n\nThis issue affects ash_sql: from 0.1.0 before 0.7.1."}],"impacts":[{"capecId":"CAPEC-1","descriptions":[{"lang":"en","value":"CAPEC-1 Accessing Functionality Not Properly Constrained by ACLs"}]}],"metrics":[{"cvssV4_0":{"Automatable":"NOT_DEFINED","Recovery":"NOT_DEFINED","Safety":"NOT_DEFINED","attackComplexity":"LOW","attackRequirements":"PRESENT","attackVector":"LOCAL","baseScore":2.1,"baseSeverity":"LOW","privilegesRequired":"NONE","providerUrgency":"NOT_DEFINED","subAvailabilityImpact":"NONE","subConfidentialityImpact":"NONE","subIntegrityImpact":"NONE","userInteraction":"NONE","valueDensity":"NOT_DEFINED","vectorString":"CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N","version":"4.0","vulnAvailabilityImpact":"NONE","vulnConfidentialityImpact":"LOW","vulnIntegrityImpact":"NONE","vulnerabilityResponseEffort":"NOT_DEFINED"},"format":"CVSS","scenarios":[{"lang":"en","value":"GENERAL"}]}],"problemTypes":[{"descriptions":[{"cweId":"CWE-863","description":"CWE-863 Incorrect Authorization","lang":"en","type":"CWE"}]}],"providerMetadata":{"dateUpdated":"2026-08-30T11:56:52.921Z","orgId":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","shortName":"EEF"},"references":[{"tags":["vendor-advisory","related"],"url":"https://github.com/ash-project/ash_sql/security/advisories/GHSA-ww8j-58rc-f8h3"},{"tags":["related"],"url":"https://cna.erlef.org/cves/CVE-2026-81318.html"},{"tags":["related"],"url":"https://osv.dev/vulnerability/EEF-CVE-2026-81318"},{"tags":["patch"],"url":"https://github.com/ash-project/ash_sql/commit/3d95478cc9e1d5bfaf6144fe9b9793f29e5ab889"}],"source":{"discovery":"EXTERNAL"},"title":"Distinct-query aggregate drops the tenant schema prefix, leaking across tenants in AshSql"}},"cveMetadata":{"assignerOrgId":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","assignerShortName":"EEF","cveId":"CVE-2026-81318","datePublished":"2026-08-30T11:56:52.921Z","dateReserved":"2026-08-30T02:30:02.111Z","dateUpdated":"2026-08-31T16:59:41.443Z","state":"PUBLISHED"},"dataType":"CVE_RECORD","dataVersion":"5.2"},"nvd":{"publishedDate":"2026-08-30 12:17:19","lastModifiedDate":"2026-09-01 21:15:00","problem_types":["CWE-863","CWE-863 CWE-863 Incorrect Authorization"],"metrics":{"cvssMetricV40":[{"source":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","type":"Secondary","cvssData":{"version":"4.0","vectorString":"CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:L/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","baseScore":2.1,"baseSeverity":"LOW","attackVector":"LOCAL","attackComplexity":"LOW","attackRequirements":"PRESENT","privilegesRequired":"NONE","userInteraction":"NONE","vulnConfidentialityImpact":"LOW","vulnIntegrityImpact":"NONE","vulnAvailabilityImpact":"NONE","subConfidentialityImpact":"NONE","subIntegrityImpact":"NONE","subAvailabilityImpact":"NONE","exploitMaturity":"NOT_DEFINED","confidentialityRequirement":"NOT_DEFINED","integrityRequirement":"NOT_DEFINED","availabilityRequirement":"NOT_DEFINED","modifiedAttackVector":"NOT_DEFINED","modifiedAttackComplexity":"NOT_DEFINED","modifiedAttackRequirements":"NOT_DEFINED","modifiedPrivilegesRequired":"NOT_DEFINED","modifiedUserInteraction":"NOT_DEFINED","modifiedVulnConfidentialityImpact":"NOT_DEFINED","modifiedVulnIntegrityImpact":"NOT_DEFINED","modifiedVulnAvailabilityImpact":"NOT_DEFINED","modifiedSubConfidentialityImpact":"NOT_DEFINED","modifiedSubIntegrityImpact":"NOT_DEFINED","modifiedSubAvailabilityImpact":"NOT_DEFINED","Safety":"NOT_DEFINED","Automatable":"NOT_DEFINED","Recovery":"NOT_DEFINED","valueDensity":"NOT_DEFINED","vulnerabilityResponseEffort":"NOT_DEFINED","providerUrgency":"NOT_DEFINED"}}],"ssvcV203":[{"source":"134c704f-9b21-4f2e-91b3-4a467353bcc0","ssvcData":{"timestamp":"2026-08-31T16:59:17.533248Z","id":"CVE-2026-81318","options":[{"exploitation":"poc"},{"automatable":"no"},{"technicalImpact":"partial"}],"role":"CISA Coordinator","version":"2.0.3"}}]},"configurations":[]},"legacy_mitre":{"record":{"CveYear":"2026","CveId":"81318","Ordinal":"1","Title":"Distinct-query aggregate drops the tenant schema prefix, leaking","CVE":"CVE-2026-81318","Year":"2026"},"notes":[{"CveYear":"2026","CveId":"81318","Ordinal":"1","NoteData":"Incorrect Authorization vulnerability in ash-project ash_sql allows a caller in a schema-based multitenant application to receive aggregate values computed from another tenant's rows.\n\nWhen an aggregate is computed over a distinct query, AshSql.AggregateQuery.add_single_aggs/5 rebuilds the outer query from query.from.source alone, which is only the {table, schema} tuple and does not carry query.prefix or query.from.prefix. For strategy(:context) multitenancy those hold the tenant schema, so the rebuilt outer query reads the repo's default schema while the inner correlated subquery still reads the tenant schema, and the two are joined only on primary key. The aggregate, and any relationship join added off the prefix-less binding, is then computed against the wrong tenant's rows. The neighbouring limit and exists branches instead wrap the query with subquery/1, which preserves the prefix.\n\nThis issue affects ash_sql: from 0.1.0 before 0.7.1.","Type":"Description","Title":"Distinct-query aggregate drops the tenant schema prefix, leaking"}]}}}