CVE-2026-79991: Authenticated SQL Injection via nested eager-loading criteria
Craft CMS GraphQL entry mutation resolvers (saveEntry, deleteEntry) read siteIddirectly from$argumentswithout passing throughArgumentManagerprepareArguments(), which is the function that enforces site-scope filtering via arrayintersect against the GraphQL schema’s allowed sites. The query path (ElementResolverprepareElementQuery) correctly calls prepareArguments(), so queries to unauthorized sites return empty. But mutations bypass this entirely — an attacker with a token scoped to Site A can create, modify, or delete entries in Site B by passing siteId in the mutations argument.
Affected Software
Event History
Frequently Asked Questions
What access does an attacker need to exploit this issue?
The attacker needs an authenticated GraphQL token that is scoped to at least one site and permission to invoke the affected entry mutations. They can then supply a different siteId in the mutation arguments.
What can an attacker do outside the site scope assigned to their token?
They can create, modify, or delete entries in another site by using the saveEntry or deleteEntry mutation with that site's siteId.
Are GraphQL entry queries affected by the same site-scope bypass?
No. The query path calls prepareArguments(), which applies the allowed-site filter; queries for unauthorized sites return empty results.