nebari-dev / nebari-dev/data-science-pack
Security(H-01): default user role and japps service carry credential-admin scopes (admin:auth_state/tokens)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 5
- Forks
- 7
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 13
Description
Summary
The pinned jhub-apps dependency grants credential-administration scopes to both the default JupyterHub user role and the japps service. Combined with auth-state persistence, this puts other users' Keycloak tokens within reach of a broad user-facing service and, potentially, of ordinary user tokens.
Severity: High · CWE-250 (Execution with Unnecessary Privileges)
Validation: Confirmed against HEAD f932d80 on 2026-07-14 (assessed at 69c84f7; unchanged since).
Evidence
images/jupyterhub/pixi.toml:32pinsjhub-apps = "==2026.5.1rc1", which builds the custom hub imagequay.io/nebari/nebari-data-science-pack-jupyterhub(values.yaml:523-525).- The pinned
install_jhub_apps(jhub-apps2026.5.1rc1jhub_apps/configuration.py) redefines the defaultuserrole to includeadmin:auth_state, and creates ajapps-service-rolewithlist:users,list:groups,read:users,read:users:activity,admin:servers,admin:server_state,admin:auth_state,access:services,list:services,read:services, andtokens. This is broader than the original assessment enumerated. config/jupyterhub/00-gateway-auth.py:540setsenable_auth_state = True;00-gateway-auth.py:370-375writes the Keycloak access, refresh, and ID tokens into auth state.config/jupyterhub/03-nebi-envs.py:66-76reads/hub/api/users/{username}with the japps service token to retrieveauth_state; the comment at03-nebi-envs.py:60-64states this fallback depends on the service token'sadmin:auth_state.
Impact
admin:auth_state is read access to a user's stored authentication state, and tokens is authority over user tokens. With auth state holding real Keycloak refresh tokens, a compromise of the user-facing japps service exposes a token that can enumerate users, read their auth state, and mint tokens. Because the default user role also carries admin:auth_state, an ordinary user token may be able to read another user's auth state directly depending on endpoint behavior. That specific token path was not dynamically exercised and should be treated as a required release test rather than a proven fact.
Remediation
- Remove
admin:auth_statefrom the defaultuserrole. - Remove
tokensand globaladmin:auth_statefrom the japps service role; grant only the minimum server-management scopes it demonstrably needs. - Replace raw IdP-token access with a narrow hub-side broker that returns a short-lived, audience-bound Nebi credential for the current subject.
- Keep refresh tokens and the hub OIDC secret inside the smallest authentication component.
- Rotate hub and Keycloak credentials if broad tokens may have been reachable by untrusted users.
Acceptance criteria
- The default
userrole contains noadmin:*ortokensscope. - Ordinary users receive
403for another user's auth state and tokens. - The japps service receives
403for cross-user auth state and token creation. - Environment listing works without exposing raw refresh tokens to japps.
- Negative tests cover admin, ordinary-user, service, browser-OAuth, and named-server tokens.
Source: data-science-pack 0.1.0 security assessment (pinned commit 69c84f72df259ec755ed40bfc83f20158c550d55), finding H-01.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the referenced role and auth-state handling in images/jupyterhub/pixi.toml, config/jupyterhub/00-gateway-auth.py, and config/jupyterhub/03-nebi-envs.py. Trace how the japps service retrieves auth_state, then use the acceptance criteria to define the required permission failures, token protection, and working environment listing across the named token types.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- authentication, authorization, backend, security
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100