CVE-2026-44840: Dgraph DQL Injection via checkUserPassword GraphQL Query
Dgraph's checkUserPassword GraphQL query passes user-supplied passwords directly into a DQL query string, letting an unauthenticated attacker inject arbitrary query blocks and enumerate or probe the…
The problem
The checkUserPassword GraphQL query in Dgraph builds a checkpwd() DQL function call using fmt.Sprintf, embedding the raw password value with no escaping. This sits in the GraphQL-to-DQL rewriting layer (query_rewriter.go), a completely separate code path from the mutation-side fixes applied for CVE-2026-41328 and CVE-2026-41327.
Because no authentication is required to call checkUserPassword, any network-reachable attacker can send a single crafted HTTP request. A double-quote character in the password breaks out of the DQL string literal, and anything after it is parsed and executed as additional DQL by the Dgraph engine.
This enables schema discovery, data enumeration via touched_uids, and resource exhaustion through expensive injected traversals.
Proof of concept
A working proof-of-concept for CVE-2026-44840 in github.com/dgraph-io/dgraph/v25, with the exact payload below.
curl -s -X POST http://TARGET:8080/graphql \
-H 'Content-Type: application/json' \
-d '{
"query": "query { checkUserPassword(name: \"admin\", password: \"x\\\") { uid } injected(func: has(User.name)) { User.name User.email } dummy(func: eq(x, \\\"x\") { msg } }") { msg } }"
}'The root cause is classic injection via string interpolation (CWE-943). In query_rewriter.go, the vulnerable line fmt.Sprintf(\checkpwd(User.password, "%s")\, password) trusts the caller to supply a safe string. A " in the password closes the DQL string literal, and the remainder of the value is appended verbatim to the query attribute, which graphquery.go then writes directly to the Dgraph query engine via b.WriteString(query.Attr).
The patch (commit cee702c93f141eeb0c96a81f70830ec9e459efac, released in v25.3.4) adds two sequential strings.ReplaceAll calls before the Sprintf: first escaping every backslash (\ to \\), then escaping every double-quote (" to \"). This prevents a user-supplied value from ever closing the DQL string literal.
The fix
Upgrade to Dgraph v25.3.4 or later. The fix escapes backslashes and double-quotes in the password value before it is interpolated into the checkpwd() DQL function call in query_rewriter.go. No configuration change is sufficient as a workaround on affected versions.
Reported by Kai Aizen.
Related research
- critical · 9.1CVE-2026-65600CVE-2026-65600: Traefik ReplacePathRegex Authentication Bypass via Path Traversal
- highCVE-2026-54763CVE-2026-54763: Traefik BasicAuth/DigestAuth/ForwardAuth Underscore Header Identity Spoofing
- high · 8.2CVE-2026-71327CVE-2026-71327: Traefik Gateway API Route Identity Collision Allows Cross-Namespace Backend Hijacking
- highCVE-2026-67309CVE-2026-67309: Traefik Kubernetes Ingress NGINX RewriteTarget Path Traversal Authentication Bypass