Summary
When role-based mount filtering is unavailable, the shared-storage resolver falls back to the user's full groups claim. The static allowlist is empty by default, so every group the user holds becomes a writable shared mount. This turns ordinary realm group membership into shared-storage authorization on any deployment where the RBAC bootstrap is off or partially configured.
Severity: Medium · CWE-863 (Incorrect Authorization)
Validation: Confirmed against HEAD f932d80 on 2026-07-14 (assessed at 69c84f7; unchanged since).
Evidence
config/jupyterhub/01-spawner.py:794-806: uses groups_with_permission_to_mount when the key is present, otherwise raw_groups = auth_state.get("groups", []) (the full claim).
config/jupyterhub/01-spawner.py:810-812: the allowlist only filters when it is non-empty; an empty list is falsy and skips filtering entirely.
- Default allowlist is empty:
01-spawner.py:147 reads custom.shared-storage-groups defaulting to [], and values.yaml:471 sets shared-storage-groups: [].
- Documented as legacy:
values.yaml:491-495 states that with RBAC off the spawner "falls back to mounting every group the user is in (legacy behaviour)."
- Corroboration:
00-gateway-auth.py:434 returns early without setting groups_with_permission_to_mount when realm_api_url is unset, so the key is genuinely absent when RBAC is off.
Impact
In nonstandard, disabled-bootstrap, or partially configured deployments, any realm group a user belongs to becomes a writable shared mount, with no explicit approval step.
Remediation
- Make the authorization mode explicit.
- In production, treat missing role-filter state as zero mounts.
- Require a non-empty approved mapping.
- Put the legacy full-
groups behavior behind an explicit unsafe-dev flag.
Acceptance criteria
Source: data-science-pack 0.1.0 security assessment (pinned commit 69c84f72df259ec755ed40bfc83f20158c550d55), finding M-03.
Summary
When role-based mount filtering is unavailable, the shared-storage resolver falls back to the user's full
groupsclaim. The static allowlist is empty by default, so every group the user holds becomes a writable shared mount. This turns ordinary realm group membership into shared-storage authorization on any deployment where the RBAC bootstrap is off or partially configured.Severity: Medium · CWE-863 (Incorrect Authorization)
Validation: Confirmed against HEAD
f932d80on 2026-07-14 (assessed at69c84f7; unchanged since).Evidence
config/jupyterhub/01-spawner.py:794-806: usesgroups_with_permission_to_mountwhen the key is present, otherwiseraw_groups = auth_state.get("groups", [])(the full claim).config/jupyterhub/01-spawner.py:810-812: the allowlist only filters when it is non-empty; an empty list is falsy and skips filtering entirely.01-spawner.py:147readscustom.shared-storage-groupsdefaulting to[], andvalues.yaml:471setsshared-storage-groups: [].values.yaml:491-495states that with RBAC off the spawner "falls back to mounting every group the user is in (legacy behaviour)."00-gateway-auth.py:434returns early without settinggroups_with_permission_to_mountwhenrealm_api_urlis unset, so the key is genuinely absent when RBAC is off.Impact
In nonstandard, disabled-bootstrap, or partially configured deployments, any realm group a user belongs to becomes a writable shared mount, with no explicit approval step.
Remediation
groupsbehavior behind an explicit unsafe-dev flag.Acceptance criteria
Source: data-science-pack 0.1.0 security assessment (pinned commit
69c84f72df259ec755ed40bfc83f20158c550d55), finding M-03.