HIGH privilege escalationchimutual tls

Privilege Escalation in Chi with Mutual Tls

Privilege Escalation in Chi with Mutual Tls

In Chi, privilege escalation via misconfigured mutual TLS (mTLS) often occurs when access controls are enforced at the transport layer but not complemented by application-level authorization. Chi services typically rely on mTLS to authenticate clients using certificates, yet if the server maps a valid client certificate to a high-privilege role without validating scopes, subject attributes, or business permissions, an attacker who compromises a low-privilege certificate can perform vertical privilege escalation.

Consider a Chi HTTP server that uses mTLS to verify client certificates but applies role-based checks only at the route level. If the server reads the certificate’s Common Name (CN) or Organization (O) and directly assigns a role (e.g., admin) based on that value, an attacker who can craft a certificate with a trusted CN can escalate to admin privileges. This is a BOLA/IDOR-like issue specific to mTLS where the trust boundary is incorrectly assumed to be sufficient for authorization.

Chi’s runtime does not inherently enforce least privilege; it is the developer’s responsibility to ensure that mTLS authentication is followed by explicit authorization checks. Without these, the API surface remains vulnerable to unauthenticated-like access from a malicious actor holding a low-privilege but valid certificate. Attack patterns include requesting admin-only endpoints using a certificate issued to a non-admin subject, or exploiting missing validation of certificate extensions (e.g., key usage, extended key usage) that should restrict usage.

Additionally, if the Chi service uses certificate-based identity but does not cross-check claims (e.g., from a certificate’s SAN or OIDC-style custom extensions) against an authorization model, horizontal privilege escalation can occur when one user accesses another user’s data. For example, an API endpoint /api/users/{userId} might trust the mTLS certificate to identify the caller but fail to ensure that the caller’s subject matches the requested userId. This is a BOLA flaw rooted in the assumption that transport-layer identity equals resource ownership.

Real-world mappings include references to OWASP API Top 10 2023:1 — Broken Object Level Authorization, which often intersects with mTLS misconfigurations. Unlike application-level tokens, mTLS identities are often treated as authoritative without secondary checks, increasing risk. The scanner checks for such gaps by correlating mTLS authentication findings with authorization checks across endpoints.

Mutual Tls-Specific Remediation in Chi

Remediation centers on ensuring that mTLS authentication is strictly separated from authorization and that identity claims are validated against an access control model. In Chi, prefer explicit authorization checks over implicit trust in certificate fields.

1. Validate certificate attributes beyond CN

Do not assign roles based solely on the certificate’s CN. Instead, inspect extended fields (e.g., SAN, custom OIDs) and map them to an authorization model. Below is a Chi handler that reads a custom SAN extension and enforces role checks:

open import Http
open import Data.String
open import Relation.Nullary

postHandler : Handler Response
postHandler = handler $
  \req -> do
    let clientCerts = getClientCertificates req
    case clientCerts of
      []      -> pure $ response401
      cert:_  -> do
        let san = getSAN cert
        case lookupRoleFromSAN san of
          Nothing        -> pure $ response403
          (Just role)    -> if role =="admin" || role =="user"
                              then authorizedHandler req role
                              else pure $ response403
  where
    getSAN : Cert -> Maybe String
    getSAN = ... -- extract SAN extension

    lookupRoleFromSAN : String -> Maybe String
    lookupRoleFromSAN san = ... -- map SAN to role

    authorizedHandler : Request String -> String -> Handler Response
    authorizedHandler req role =
      if req.path =="/admin" && role /="admin"
        then pure $ response403
        else pure $ response200

2. Enforce least privilege with per-endpoint checks

For endpoints that act on user-specific resources, validate that the certificate identity matches the resource owner. Here’s an example for a user profile endpoint in Chi:

userProfileHandler : String -> Handler Response
userProfileHandler requestedUserId = handler $
  \req -> do
    clientCerts <- getClientCertificates req
    case clientCerts of
      []          -> pure $ response401
      cert : _    -> do
        let callerId = getSubjectId cert
        if callerId == requestedUserId || callerHasScope cert "profile:read"
          then pure $ response200
          else pure $ response403
  where
    getSubjectId : Cert -> String
    getSubjectId = ...

    callerHasScope : Cert -> String -> Boolean
    callerHasScope cert scope = ...

3. Combine mTLS with scopes or claims

Use certificate extensions or signed claims (e.g., from a private CA) to embed scopes, and validate them in Chi handlers. For example, a custom OID carrying scope=users:read can be checked before allowing read access:

scopeCheckHandler : Handler Response
scopeCheckHandler = handler $
  \req -> do
    certs <- getClientCertificates req
    case certs of
      []          -> pure $ response401
      cert : _    -> if hasScope cert "users:read"
                        then pure $ response200
                        else pure $ response403
  where
    hasScope : Cert -> String -> Boolean
    hasScope cert scope = ...

4. Avoid default admin mapping

Never map a certificate CN like admin directly to an admin role. Instead, maintain a server-side allowlist that maps certificate fingerprints or SANs to roles:

roleMapping : List (String, String) -- (certFingerprint, role)
roleMapping = [ ("a1b2c3...", "user")
              , ("d4e5f6...", "admin")
              ]

resolveRole : String -> Maybe String
resolveRole fingerprint = lookup fingerprint roleMapping

5. Use Chi’s request context for identity

Store resolved identity in the request context after mTLS validation, and use it in handlers:

validateMTLS : Request a -> Maybe RequestWithIdentity
validateMTLS req = ... -- validate cert chain, extract identity

main : IO ()
main = do
  routed $ \req -> case validateMTLS req of
    Nothing          -> response401
    Just reqIdentity -> route $
      [ ("admin", adminHandler reqIdentity)
      , ("users", userHandler reqIdentity)
      ]

adminHandler : RequestWithIdentity -> Handler Response
adminHandler req = do
  unless (isAdmin req) (pure response403)
  -- proceed with admin logic

These patterns ensure that mTLS is used for authentication while Chi-specific authorization logic enforces least privilege, preventing privilege escalation across user, role, and permission boundaries.

Frequently Asked Questions

Can mTLS alone prevent privilege escalation in Chi APIs?
No. mTLS authenticates clients but does not enforce authorization. You must add explicit, per-endpoint checks in Chi to map certificates to least-privilege roles and validate resource ownership.
How does middleBrick assess mTLS-related privilege escalation risks?
The scanner correlates mTLS authentication events with missing or weak authorization checks across Chi endpoints, highlighting cases where valid certificates map to excessive privileges without downstream validation.