---
id: "CVE-2026-96628"
kind: "vulnerability"
aliases: ["CVE-2026-96628", "GHSA-mp22-58ff-6fhr", "GO-2026-6806"]
title: "Arcane: Environment access token bypasses the admin-required authorization gate on `/api/debug/pprof`"
severity: "medium"
cvss: 4.300000190734863
epss: 0.00203999993391335
exploited: false
status: "open"
category: "ai-tooling"
products: [{"name": "github.com/getarcaneapp/arcane/backend/v2", "fixed": ["2.11.0"], "affected": "< 2.11.0", "ecosystem": "go"}, {"name": "github.com/getarcaneapp/arcane/backend", "fixed": [], "affected": "all versions", "ecosystem": "go"}]
ecosystems: ["go"]
tags: ["ai-tooling", "arcane", "cwe-863", "docker", "go", "self-hosted"]
not_affected_if: ["default-config"]
published_at: "2026-10-16T21:12:03+00:00"
first_seen_at: "2026-10-23T19:11:32+00:00"
updated_at: "2026-10-23T20:56:37+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-mp22-58ff-6fhr", "first_seen_at": "2026-10-23T19:11:32+00:00"}, {"source": "govuln", "url": "https://pkg.go.dev/vuln/GO-2026-6806", "first_seen_at": "2026-10-23T19:13:08+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-96628", "first_seen_at": "2026-10-23T21:57:14+00:00"}]
---

# Arcane: Environment access token bypasses the admin-required authorization gate on `/api/debug/pprof`

Arcane's manager accepts an environment access token in the X-Arcane-Agent-Token header and skips the admin-only check on /api/debug/pprof routes. An attacker holding a valid environment token can read Go runtime profiling data (goroutine stacks, heap, command line) that is meant for global admins only.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- go:github.com/getarcaneapp/arcane/backend/v2 affected < 2.11.0 fixed 2.11.0
- go:github.com/getarcaneapp/arcane/backend affected all versions fixed ?

## How to check

Check the Arcane version: affected if the backend module github.com/getarcaneapp/arcane/backend/v2 is below 2.11.0.
As a test, request GET /api/debug/pprof/heap?debug=1 with only an X-Arcane-Agent-Token header; a 200 response with profile output confirms exposure.

## Fix

Upgrade Arcane to 2.11.0 or later.
Until then, rotate environment access tokens and block /api/debug/pprof/* at the reverse proxy.

## Timeline

- 2026-10-23T19:11:32+00:00 ghsa https://github.com/advisories/GHSA-mp22-58ff-6fhr
- 2026-10-23T19:13:08+00:00 govuln https://pkg.go.dev/vuln/GO-2026-6806
- 2026-10-23T21:57:14+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-96628

## From the sources

## Summary

Arcane v2.10.2 contains an authorization inconsistency in `AuthMiddleware.managerAuth`.

When a request supplies a valid environment access token through the `X-Arcane-Agent-Token` header, `managerAuth` resolves the associated environment, installs an environment-scoped permission set, and immediately calls `next(c)`.

This occurs before the middleware evaluates the `AdminRequired` option and verifies that the caller is a global administrator.

As a result, an environment-scoped access token can access routes protected with `WithAdminRequired()`, despite the corresponding `EnvironmentPermissionSet` intentionally containing no global or sudo permissions.

In v2.10.2, the affected admin-only surface is the manager's Go `pprof` diagnostic interface under:

`/api/debug/pprof/*`

This exposes diagnostic and runtime profiling information that the application explicitly intends to restrict to global administrators.

The issue is an incorrect authorization vulnerability (CWE-863).

## Details

### 1. Environment access tokens are accepted by the manager authentication middleware

The production authentication middleware is configured with an environment access-token resolver:

`backend/internal/di/providers.go`

Conceptually, the middleware is constructed as:

```go
auth.NewAuthMiddleware(authService, cfg).
    WithApiKeyValidator(apiKey).
    WithEnvironmentAccessTokenResolver(env).
    WithPermissionResolver(role)
```

Therefore, the `X-Arcane-Agent-Token` authentication path is active in the production manager.

### 2. The environment-token path returns before authorization options are evaluated

The relevant logic is in:

`backend/internal/auth/middleware.go`

`managerAuth` first checks the `X-Arcane-Agent-Token` header.

When the token resolves to an environment, the middleware installs an environment-scoped permission set and immediately continues processing:

```go
if agentToken := req.Header.Get(utils.HeaderAgentToken); agentToken != "" {
    if env, ok := m.resolveEnvironmentAccessToken(ctx, agentToken).Get(); ok {
        environmentScopedInternal(c, env)
        return next(c)
    }
}
```

The important part is the unconditional:

```go
return next(c)
```

The normal authentication path later evaluates the middleware's `AdminRequired` option:

```go
ps := m.resolvePermissionsOrDeny(ctx, user)

if m.options.AdminRequired && !ps.IsGlobalAdmin() {
    return c.JSON(http.StatusForbidden, common.APIError{
        Code:    "FORBIDDEN",
        Message: "You don't have permission to access this resource",
    })
}
```

The environment-token branch never reaches this check.

Consequently, `WithAdminRequired()` has no effect when authentication succeeds through a valid environment access token.

This creates an authorization inconsistency between authentication mechanisms:

- normal user/session authentication → `AdminRequired` is enforced;
    
- environment access-token authentication → `AdminRequired` is bypassed.
    

### 3. Environment tokens are intentionally not global-administrator credentials

`backend/pkg/authz/permission_set.go` defines the effective permissions assigned to an environment access token.

`EnvironmentPermissionSet(envID)` grants environment-scoped permissions only for the specified environment:

```go
func EnvironmentPermissionSet(envID string) *PermissionSet {
    ps := NewPermissionSet()

    if envID == "" {
        return ps
    }

    for _, p := range AllPermissions() {
        if IsEnvScoped(p) {
            ps.AddEnv(envID, p)
        }
    }

    return ps
}
```

The implementation explicitly establishes that these credentials do not receive global or sudo permissions.

Therefore, an environment access token should not satisfy a global-administrator authorization requirement.

The early return in `managerAuth` bypasses this intended privilege boundary.

### 4. `/api/debug/pprof/*` explicitly requires global-administrator authorization

The diagnostic routes are registered in:

`backend/api/ws/diagnostics.go`

The `pprof` group is protected using:

```go
pprofGroup := group.Group(
    "/debug/pprof",
    authMiddleware.WithAdminRequired().Add(),
)
```

The source also documents the intended authorization requirement by noting that pprof keeps the stricter admin-required gate.

The group exposes handlers including:

```text
/api/debug/pprof/
/api/debug/pprof/cmdline
/api/debug/pprof/profile
/api/debug/pprof/symbol
/api/debug/pprof/trace
/api/debug/pprof/heap
/api/debug/pprof/goroutine
/api/debug/pprof/allocs
/api/debug/pprof/block
/api/debug/pprof/mutex
/api/debug/pprof/threadcreate
```

Named profiles are dispatched through `pprof.Handler`.

Because `WithAdminRequired()` is bypassed by the environment-token branch, a valid environment access token can reach these handlers even though its permission set is not globally privileged.

### 5. Other middleware does not restore the missing authorization check

The CSRF middleware recognizes `X-Arcane-Agent-Token` as a header-based credential and does not apply the normal cross-origin CSRF validation to such requests.

Additionally, the environment proxy middleware passes through requests that do not target an `/environments/{id}/...` path.

Therefore a request to:

```text
/api/debug/pprof/*
```

can proceed to `managerAuth`, enter the environment-token authentication branch, and reach the pprof handler without another global-administrator authorization check being applied.

## Source-to-sink authorization path

The vulnerable control flow is:

```text
X-Arcane-Agent-Token
        |
        v
environment access token resolver
        |
        v
environment resolved successfully
        |
        v
EnvironmentPermissionSet(environmentID)
        |
        v
return next(c)
        |
        |  AdminRequired check is skipped
        v
/api/debug/pprof/*
        |
        v
net/http/pprof handler
```

The security boundary violation occurs at the early `return next(c)`.

## Proof of Concept

### Preconditions

The test requires:

1. A valid Arcane environment access token.
    
2. An Arcane manager running the affected code.
    
3. No global-administrator account or credentials.
    

### Test 1 — environment access token

Send a request to an admin-protected pprof endpoint using only an environment access token:

```http
GET /api/debug/pprof/heap?debug=1 HTTP/1.1
Host: arcane.example.com
X-Arcane-Agent-Token: <VALID_ENVIRONMENT_ACCESS_TOKEN>
```

No administrator session cookie or administrator Bearer token is supplied.

### Vulnerable behavior

On an affected instance, the request is expected to reach the pprof handler instead of being rejected by `WithAdminRequired()`.

A successful response demonstrates that the environment-token authentication branch bypasses the administrator requirement.

For example, the response may contain the Go heap profiling output generated by `net/http/pprof`.

### Test 2 — non-admin user contrast case

Send the same request using a normal authenticated non-global-admin user:

```http
GET /api/debug/pprof/heap?debug=1 HTTP/1.1
Host: arcane.example.com
Authorization: Bearer <NON_ADMIN_ACCESS_TOKEN>
```

The expected result is:

```http
HTTP/1.1 403 Forbidden
```

with an authorization error indicating that the user does not have permission to access the resource.

This contrast demonstrates the authorization inconsistency:

```text
environment-scoped token
        -> admin gate skipped
        -> pprof handler reached

normal non-admin user
        -> admin gate evaluated
        -> HTTP 403
```

### Expected secure behavior

A valid environment access token should receive:

```http
HTTP/1.1 403 Forbidden
```

for every route protected with `WithAdminRequired()`.

Only a caller whose effective permission set satisfies `IsGlobalAdmin()` should be allowed to access these routes.

## Impact

An attacker who obtains a valid environment access token can cross the intended authorization boundary between an individual environment and manager-w

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
