# runc container escape via "masked path" abuse due to mount race conditions

runc bind-mounts container /dev/null over maskedPaths without verifying the inode; racing a symlink there yields arbitrary host mounts and container escape.

- Payout: Research
- Severity: high
- Program: runc
- Found by: ssst0n3, rata, lifubang
- Disclosed: 2025-11-05
- CVE: CVE-2025-31133
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-9493-h29p-rfm2
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-9493-h29p-rfm2
- Tags: area:cloud domain:infra impact:dos impact:privesc impact:rce kind:research platform:ghsa sev:high tech:docker tech:linux technique:race-window vuln:misconfiguration vuln:privilege-escalation vuln:race-condition

**Target:** OCI container runtime maskedPaths /dev/null bind-mount
**Root cause:** runc did not verify that the bind-mount source for file maskedPaths was a real /dev/null inode, and ignored ENOENT on the source, so a raced symlink or deleted /dev/null subverted masking.
**Steps:**
1. Spawn a container sharing mounts with another container (parallel execution via shared mounts, e.g. `docker buildx build`).
2. Race to replace or modify the container's `/dev/null` inode with a symlink to an attacker-controlled path (e.g. `/proc/sys/kernel/core_pattern`).
3. runc bind-mounts the symlink target over the masked path inside the container.
4. Write to the now-exposed file to reconfigure the coredump helper, then trigger a coredump to run a binary with host root privileges.
5. Variant: delete `/dev/null` before runc's bind-mount; runc ignores ENOENT and skips maskedPaths, exposing `/proc/kcore` etc.
**How found:** Researchers noticed runc never validated the /dev/null source inode for file maskedPaths and that ENOENT on the source was silently ignored, then tested racing the inode across containers sharing mounts.
**Exploitation:** Attacker with container-spawn control races /dev/null to make runc bind-mount /proc/sys/kernel/core_pattern read-write inside the container; kernel upcalls are not namespaced, so triggering a coredump executes an attacker-chosen binary as host root. Alternatively bind-mount /proc/sysrq-trigger for host DoS.
**Escalation:** Arbitrary mount gadget turns a masking mount into a write primitive on host procfs, escalating from container to full host root via core_pattern upcall.
**Insight:** When a runtime bind-mounts a well-known path as a security primitive, check whether it verifies the source inode and how it handles ENOENT on that source — a shared-mount race can turn the primitive into an arbitrary mount gadget.

