nebari-dev / nebari-dev/data-science-pack

Security(M-03): missing role-filter state falls back to mounting every group in the token

Open
#171 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area: security priority: medium ⚡
Dominant language
Python
Stars
5
Forks
7
Avg merge
1d 20h
Merged PRs (30d)
13

Description

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

  • Absent, malformed, or unavailable role-filter data yields no shared mounts and a visible readiness/status error.

Source: data-science-pack 0.1.0 security assessment (pinned commit 69c84f72df259ec755ed40bfc83f20158c550d55), finding M-03.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read config/jupyterhub/01-spawner.py:794-812 and config/jupyterhub/01-spawner.py:147, then inspect config/jupyterhub/00-gateway-auth.py:434 and values.yaml:471,491-495. Trace how absent or empty role-filter data reaches shared-mount resolution. Done means unavailable or malformed role-filter data produces no shared mounts and a visible readiness or status error, with legacy full-groups behavior requiring an explicit unsafe-dev setting.

Written by the indexing model from the issue text.

Assessment

Tech stack
jupyter, python
Domain
authorization, backend, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.