Skip to content

fix: block bind mounts to sensitive host paths for non-owner/admin members - #5254

Open
Siumauricio wants to merge 1 commit into
canaryfrom
fix/mount-bind-path-privilege
Open

fix: block bind mounts to sensitive host paths for non-owner/admin members#5254
Siumauricio wants to merge 1 commit into
canaryfrom
fix/mount-bind-path-privilege

Conversation

@Siumauricio

@Siumauricio Siumauricio commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

The Mounts feature (bind mounts on applications, compose, and database services) let any member with volume:create access set an arbitrary bind mount hostPath, with zero validation. generateBindMounts wires that path straight into the Swarm service spec, so a non-privileged member could mount /var/run/docker.sock, /etc/dokploy, or other host-critical paths and escalate to root on the Dokploy control host — same impact as bringing your own docker-compose.yml with a docker.sock mount, but reachable through the plain Mounts UI on any service type, no Compose needed.

  • Added isDangerousBindMountPath() (fixed blocklist: docker.sock, /etc/dokploy, /root, /boot, /proc, /sys, docker's data dir) and isPrivilegedOrgRole().
  • mount.create / mount.update now reject a bind mount targeting one of those paths unless the caller is the organization's owner or admin.
  • Single-user self-hosted installs are unaffected — the sole user is always the owner, so nothing changes for the common case (DinD, watchtower, etc. keep working). This only restricts members/custom roles that shouldn't have host-level access in the first place.

Verified live: as the org owner, mounting both a safe path and /var/run/docker.sock still succeeds (no regression).

Greptile Summary

The PR adds role-sensitive validation intended to prevent non-owner/admin members from binding security-critical host paths into managed workloads.

  • Adds lexical normalization and a sensitive-host-path blocklist.
  • Enforces the restriction during mount creation and updates.
  • Adds an organization membership lookup for owner/admin privilege.

Confidence Score: 3/5

The PR is not safe to merge until parent-directory bind mounts that expose protected paths such as the Docker socket are blocked.

A non-privileged member can bind /run or /var/run, which passes the new predicate and is forwarded directly to Docker, exposing docker.sock inside the workload.

Files Needing Attention: packages/server/src/services/mount.ts

Security Review

The restriction remains bypassable by binding a parent directory such as /run or /var/run; the resulting workload can still access the enclosed Docker socket and obtain host-level control.

Reviews (1): Last reviewed commit: "fix: block bind mounts to sensitive host..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Context used:

…mbers

The Mounts feature (application/compose/database services) let any
member with volume:create access set an arbitrary bind mount hostPath,
with zero validation. Since generateBindMounts wires that path straight
into the Swarm service spec, a non-privileged member could mount
/var/run/docker.sock, /etc/dokploy, or other host-critical paths and
escalate to root on the Dokploy control host - same impact as bringing
your own docker-compose.yml with a docker.sock mount, but reachable
through the plain Mounts UI on any service type.

Add isDangerousBindMountPath() with a fixed blocklist of host-critical
paths (docker.sock, /etc/dokploy, /root, /boot, /proc, /sys, docker's
data dir) and isPrivilegedOrgRole(); mount.create/update now reject a
bind mount targeting one of those paths unless the caller is the org's
owner or admin. Single-user self-hosted installs are unaffected - the
sole user is always the owner.
Comment on lines +46 to +48
return DANGEROUS_HOST_PATH_PREFIXES.some(
(prefix) => normalized === prefix || normalized.startsWith(`${prefix}/`),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Parent paths bypass socket block

When a non-owner/admin member binds /run or /var/run, this descendant-only comparison classifies the path as safe even though it contains the blocked docker.sock; generateBindMounts then forwards that directory directly to Docker, exposing daemon control inside the workload and enabling host takeover.

How this was verified: The accepted parent path is passed unchanged as the Docker bind mount Source, making its docker.sock child available under the mount target.

Knowledge Base Used:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant