GitHub Advisoryadvisory · Go
GHSA-mp22-58ff-6fhr Arcane: Environment access token bypasses the admin-required authorization gate on `/api/debug/pprof`
MEDIUM
Official page ↗
- Aliases
- CVE-2026-96628
- Ecosystem
- Go
- Packages
- github.com/getarcaneapp/arcane/backend/v2
- Severity
- Moderate
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
- Weaknesses
- CWE-863
- Reviewed
- 2026-10-16
Affected packages
• Go github.com/getarcaneapp/arcane/backend/v2: < 2.11.0 → fixed in 2.11.0
Description
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:
```
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
```
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-wide administrative functionality.
In the currently ide…
Related
Alias · CVE (1)
- CVE-2026-96628 Arcane is an interface for managing Docker containers, images, networks, and volumes. vulnerability
Weakness · CWE (1)
- CWE-863 Incorrect Authorization weakness
References
- https://github.com/getarcaneapp/arcane/security/advisories/GHSA-mp22-58ff-6fhr web
- https://github.com/getarcaneapp/arcane/pull/3881 web
- https://github.com/getarcaneapp/arcane/commit/4fe4c7ed9483dff7d43e3c4bee6a92037ce886b4 web
- https://github.com/getarcaneapp/arcane package
- https://github.com/getarcaneapp/arcane/releases/tag/backend/v2.11.0 web