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

Security(M-07): Hub OIDC login credential reused for Admin API and forwarded to japps with broad realm roles

Open
#175 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

The hub's OIDC login client doubles as its Keycloak Admin API service account, and the same client secret is forwarded into the user-facing japps service. The login client is granted broad realm-management read roles, so compromise of this widely distributed credential permits realm-wide enumeration of users, groups, clients, and configuration.

Severity: Medium · CWE-250 (Execution with Unnecessary Privileges)
Validation: Confirmed against HEAD f932d80 on 2026-07-14 (assessed at 69c84f7; unchanged since).

Evidence

  • Login credentials reused for Admin API: config/jupyterhub/00-gateway-auth.py:480-490 builds the Admin API client from the same OAuth client_id/client_secret, and _client_credentials_token (00-gateway-auth.py:149-161) performs a client_credentials grant with them.
  • Secret forwarded to japps: config/jupyterhub/02-jhub-apps.py:79-84 injects JUPYTERHUB_OIDC_CLIENT_SECRET into the japps subprocess environment.
  • Broad roles: files/keycloak_rbac_bootstrap.py:64 assigns view-clients, view-groups, view-realm, view-users. Note the values.yaml:266 comment advertises only three of these (it omits view-users), so the docs understate what the code grants.

Impact

The platform needs limited authorization-lookup capability, but binding realm-management roles to the login credential and then forwarding that credential to a user-facing service means a single compromise can enumerate every user, group, and client in the realm.

Remediation

  • Separate login credentials from administration credentials.
  • Use a purpose-specific identity or an authorization broker that exposes only the required group/profile decision.
  • Never forward administrative credentials into a user-facing service.
  • Rotate the existing secret.
  • Fix the values.yaml comment to match the roles actually granted.

Acceptance criteria

  • The login client has no realm-management roles.
  • Compromise of the login client cannot enumerate unrelated realm objects.

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

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

Start by reading config/jupyterhub/00-gateway-auth.py, config/jupyterhub/02-jhub-apps.py, files/keycloak_rbac_bootstrap.py, and values.yaml at the referenced lines. Trace how the login client is used and how its secret and realm roles are configured; identify a design that meets the required authorization lookup without exposing administrative credentials. Done means the login client has no realm-management roles and cannot enumerate unrelated realm objects.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, yaml
Domain
authentication, authorization, security
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.