Skip to main content

Arcane CVE-2026-47179

| EUVD-2026-33369 HIGH
Path Traversal (CWE-22)
2026-05-28 https://github.com/getarcaneapp/arcane GHSA-c3px-h233-h6fq
7.7
CVSS 3.1
Share

CVSS VectorNVD

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Confidentiality
High
Integrity
None
Availability
None

Lifecycle Timeline

3
Source Code Evidence Fetched
May 28, 2026 - 23:20 vuln.today
Analysis Generated
May 28, 2026 - 23:20 vuln.today
CVE Published
May 28, 2026 - 22:39 nvd
HIGH 7.7

DescriptionNVD

Summary

ProjectService.GetProjectFileContent returns the contents of any Docker Compose include directive declared in a project's compose file before any path-traversal validation runs. Because ProjectService.CreateProject writes attacker-supplied compose content to disk without validating include paths, an authenticated user can create a project whose compose file declares include: ['../../../../etc/passwd'], then read the include via the project file API. The result is arbitrary read of any file readable by the Arcane backend process, including /app/data/arcane.db (the SQLite database containing every user's password hash and API key), enabling escalation to admin and, via Arcane's Docker control plane, RCE on the host.

Details

Root cause #1 - CreateProject writes compose content without validation (backend/internal/services/project_service.go:1605-1644):

go
func (s *ProjectService) CreateProject(ctx context.Context, name, composeContent string, envContent *string, user models.User) (*models.Project, error) {
    // ... directory setup ...
    if err := projects.SaveOrUpdateProjectFiles(projectsDirectory, projectPath, composeContent, envContent); err != nil {
        _ = s.db.WithContext(ctx).Delete(proj).Error
        return nil, fmt.Errorf("failed to save project files: %w", err)
    }
    // ...
}

Compare with UpdateProject (project_service.go:2494, :2577), which calls validateComposeContentForUpdate. That validator (line 2599) loads the compose with missingIncludeStubResourceLoaderInternal, which calls ValidateIncludePathForWrite (includes.go:139) and rejects includes outside the project directory. CreateProject bypasses this entirely, so any malicious include: array survives to disk.

Root cause #2 - GetProjectFileContent reads include files before path validation (backend/internal/services/project_service.go:831-872):

go
includes, parseErr := projects.ParseIncludes(composeFile, envMap, true)
if parseErr == nil {
    for _, inc := range includes {
        if inc.RelativePath == relativePath {
            return project.IncludeFile{
                Path:         inc.Path,
                RelativePath: inc.RelativePath,
                Content:      inc.Content,    // <-- arbitrary file content returned here
            }, nil
        }
    }
}

fullPath := filepath.Join(proj.Path, relativePath)
// ... IsSafeSubdirectory check at line 870 - never reached when include matches ...

Root cause #3 - ParseIncludes reads include files from anywhere by design (backend/pkg/projects/includes.go:24-72):

go
// Security Model for Include Files:
// - READ: Docker Compose allows include files from anywhere (parent dirs, absolute paths, etc.)
//         We allow reading from any path to maintain compatibility with standard Docker Compose behavior
// - WRITE/DELETE: Restricted to files within the project directory only for security

parseIncludeItemInternal at includes.go:97-101 builds fullPath = filepath.Clean(filepath.Join(baseDir, includePath)) and os.ReadFile(fullPath) at line 105 - no containment check. The returned RelativePath (line 124) is filepath.ToSlash(filepath.Clean(includePath)), which preserves ../../../../etc/passwd verbatim for the equality match in GetProjectFileContent.

Authorization surface: The handler GET /api/environments/{id}/projects/{projectId}/file (backend/internal/huma/handlers/projects.go:268-279) and POST /api/environments/{id}/projects (line 242-253) only declare BearerAuth/ApiKeyAuth. There is no admin-role gate on either handler - GetProjectFile (line 582) and CreateProject (line 524) simply call humamw.GetCurrentUserFromContext. The default user role assigned in users.go:223 is "user" (not admin), and that role is sufficient to exploit.

Resulting primitive: arbitrary read of any file readable by the Arcane backend process (uid/gid of the container). Sensitive targets include /app/data/arcane.db (SQLite containing argon2 password hashes and API keys for every user), /app/data/secrets/*, mounted host configuration, SSH keys (if mounted), and Docker socket-adjacent secrets.

Impact

  • Arbitrary file read as the Arcane backend process for any authenticated user, including users with the lowest-privilege "user" role.
  • Credential disclosure: arcane.db contains argon2 password hashes for every account (including admins) and API key material - supports offline cracking and direct token exfiltration.
  • Privilege escalation: a "user"-role attacker can recover or replay admin credentials, then exercise full Arcane functionality (Docker container/exec/volume control), which on a typical deployment with the host Docker socket mounted is host RCE.
  • Configuration / secret exposure: any environment files, OIDC client secrets, registry credentials, or files mounted into the container are reachable.
  • The scope crosses the security authority of other user accounts (S:C), since one authenticated user reads credentials belonging to other users and to the admin.

AnalysisAI

Authenticated arbitrary file read in Arcane (Docker management UI) versions ≤ 1.19.3 allows any low-privileged user to read any file accessible to the backend process by abusing Docker Compose include: directives. Because CreateProject skips include-path validation that UpdateProject enforces, an attacker can register a project whose compose file points at /etc/passwd or /app/data/arcane.db, then fetch the contents via the project file API - yielding stored password hashes and API keys for all users, enabling admin takeover and host RCE through Arcane's Docker control plane. …

Sign in for full analysis, threat intelligence, and remediation guidance.

RemediationAI

Within 24 hours: Inventory all Arcane deployments and identify instances running versions ≤1.19.3. Within 7 days: Upgrade all affected instances to Arcane 1.19.4. …

Sign in for detailed remediation steps.

Share

CVE-2026-47179 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy