GitHub Security Advisory: GHSA-8wpc-j9q9-j5m2
Package: github.com/devtron-labs/devtron (GO)
Severity: HIGH (CVSS 0.0)
CWE: CWE-862: Missing Authorization
Vulnerable versions: <= 2.0.0
Patched in: unpatched

Summary:  Devtron Attributes API Unauthorized Access Leading to API Token Signing Key Leakage

Details:
# Devtron Attributes API Unauthorized Access Leading to API Token Signing Key Leakage

## Summary

This vulnerability exists in Devtron's Attributes API interface, allowing any authenticated user (including low-privileged CI/CD Developers) to obtain the global API Token signing key by accessing the `/orchestrator/attributes?key=apiTokenSecret` endpoint. After obtaining the key, attackers can forge JWT tokens for arbitrary user identities offline, thereby gaining complete control over the Devtron platform and laterally moving to the underlying Kubernetes cluster.

**CWE Classification**: CWE-862 (Missing Authorization)

## Details

### Vulnerability Mechanism

Devtron uses a JWT-based API Token mechanism for authentication. All API Tokens are signed using HMAC-SHA256 with the `apiTokenSecret` stored in the database. This key is exposed through the Attributes API, but the authorization check code for this API has been commented out, allowing any authenticated user to read it.

### Source Code Analysis

**Vulnerability Location**: `api/restHandler/AttributesRestHandlder.go:173-195`

```go
func (handler AttributesRestHandlerImpl) GetAttributesByKey(w http.ResponseWriter, r *http.Request) {
    // Only checks if user is logged in
    userId, err := handler.userService.GetLoggedInUser(r)
    if userId == 0 || err != nil {
        common.HandleUnauthorized(w, r)
        return
    }

    // CRITICAL: RBAC check is commented out
    /*token := r.Header.Get("token")
    if ok := handler.enforcer.Enforce(token, rbac.ResourceGlobal, rbac.ActionGet, "*"); !ok {
        WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
        return
    }*/

    // Directly retrieves any attribute without authorization
    vars := mux.Vars(r)
    key := vars["key"]
    res, err := handler.attributesService.GetByKey(key)
    if err != nil {
        handler.logger.Errorw("service err, GetAttributesById", "err", err)
        common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
        return
    }
    common.WriteJsonResp(w, nil, res, http.StatusOK)
}
```

**Key Usage**: `pkg/apiToken/ApiTokenSecretService.go:54-88`

```go
func (impl ApiTokenSecretServiceImpl) GetApiTokenSecretByteArr() ([]byte, error) {
    if len(impl.apiTokenSecretStore.Secret) == 0 {
        return nil, errors.New("secret found empty")
    }
    return []byte(impl.apiTokenSecretStore.Secret), nil
}

func (impl ApiTokenSecretServiceImpl) getApiSecretFromDb() (string, error) {
    apiTokenSecret, err := impl.attributesService.GetByKey(bean.API_SECRET_KEY)
    if err != nil {
        return "", err
    }
    if apiTokenSecret == nil || len(apiTokenSecret.Value) == 0 {
        return "", errors.New("api token secret from DB found nil/empty")
    }
    return apiTokenSecret.Value, nil
}
```

This key is used to sign and verify all Devtron API Tokens and is the core credential of the control plane.

## PoC (Proof of Concept)

### Environment Setup

#### Prerequisites

- Kubernet