high
CVE
CVE-2026-58302
CWE
CWE-22, CWE-427
Affected Surface
linuxcnc-uspace before 2.9.9, LinuxCNC deployments that install rtapi_app with SUID root or equivalent elevated privileges, Debian and Ubuntu systems that package LinuxCNC userspace components, CNC controllers, lab systems, and developer hosts where untrusted local users or code can invoke rtapi_app
CVE-2026-58302 is a fresh Linux privilege-escalation issue in linuxcnc-uspace that NVD published on 30 June 2026. The vulnerable binary is rtapi_app, a LinuxCNC helper that loads realtime modules. On affected builds, it runs with elevated privileges and accepts a user-controlled module name that is later turned into a shared-library path for dlopen().
The vulnerability is conceptually simple and technically important: if a privileged program builds a path like ${trusted_dir}/${user_input}.so without rejecting / or .., the trusted directory is no longer a boundary. Local attackers can climb out of that directory and make the process load an arbitrary shared object under root privileges.
Affected package and versions
The affected package is:
linuxcnc-uspacebefore2.9.9
NVD explicitly scopes the issue to rtapi_app in linuxcnc-uspace, and the public fix commits show the remediation landing as module-name sanitization. If you package LinuxCNC from source instead of distro packages, compare your tree against the 2.9.9 release or the referenced fix commits.
Start with inventory:
dpkg -l | rg 'linuxcnc|linuxcnc-uspace'
command -v rtapi_app
Then check whether the installed binary is privileged:
ls -l "$(command -v rtapi_app)"
getcap "$(command -v rtapi_app)" 2>/dev/null
The vulnerable code path
The pre-fix logic took the requested module name and interpolated it directly into a path:
static int do_load_cmd(string name, vector<string> args) {
void *w = modules[name];
if (w == NULL) {
char what[LINELEN+1];
snprintf(what, LINELEN, "%s/%s.so", EMC2_RTLIB_DIR, name.c_str());
void *module = modules[name] = dlopen(what, RTLD_GLOBAL | RTLD_NOW);
...
}
}
That means an attacker-controlled name such as:
../../tmp/evil
would resolve to a path like:
${EMC2_RTLIB_DIR}/../../tmp/evil.so
If the binary still holds root privileges at that point, any constructor code inside evil.so, or the exported module entrypoint that LinuxCNC later resolves, executes with those same privileges.
The fix
The upstream fix is intentionally small. Before building the path, LinuxCNC now rejects slash characters and .. segments:
if (name.find("/") != std::string::npos || name.find("..") != std::string::npos) {
rtapi_print_msg(
RTAPI_MSG_ERR,
"%s: Not allowed as module name. Slashes or with \"..\" (even /a..b/) are not allowed.\n",
name.c_str()
);
return -1;
}
what = fmt::format("{}/{}.so", EMC2_RTLIB_DIR, name);
void *module = modules[name] = dlopen(what.c_str(), RTLD_GLOBAL | RTLD_NOW);
This is the correct fix because it restores the intended trust boundary: only module basenames are allowed, not attacker-controlled paths.
Why this is more than a niche CNC bug
LinuxCNC is specialized software, but the vulnerability pattern is generic and high value:
- the target host is Linux
- the vulnerable binary is privileged
- exploitation does not require network access
- arbitrary library load under root usually means immediate full host compromise
That matters for AppSec teams because many real intrusion chains begin with low-privilege code execution. A malicious package, a compromised developer account, an SSRF-to-shell chain, or a weak web app running on the same workstation is often “only local” until a SUID-root primitive turns it into root.
In other words, CVE-2026-58302 is relevant anywhere LinuxCNC is deployed on systems that also handle source code, package management, build jobs, secrets, or remote administration.
Exploit model
The vulnerable flow is short:
unprivileged local user
-> writes malicious /tmp/evil.so
-> invokes rtapi_app with module name ../../tmp/evil
-> rtapi_app formats ${EMC2_RTLIB_DIR}/../../tmp/evil.so
-> dlopen() loads attacker library before privileges are dropped
-> attacker code runs as root
The critical boundary failure is not in dlopen() itself. dlopen() is doing exactly what it was asked to do. The bug is that the program treated a path component as though it were a harmless module identifier.
Detection and scoping
Check installed versions and privilege state:
dpkg -l | rg 'linuxcnc|linuxcnc-uspace'
command -v rtapi_app && ls -l "$(command -v rtapi_app)"
Search for the patched behavior if you maintain custom source builds:
rg -n 'name\\.find\\(\"/\"\\)|name\\.find\\(\"\\.\\.\"\\)' /path/to/linuxcnc/source
Prioritize systems where all of these are true:
- LinuxCNC is installed
rtapi_appis SUID root or otherwise runs elevated- untrusted local users or code can execute on the host
- the host stores useful secrets or controls physical equipment
Examples include:
- shared lab or workshop workstations
- engineering laptops used for both development and machine control
- university or training environments with multiple local users
- industrial systems where a web app, agent, or automation job can reach a shell
Remediation
Upgrade to LinuxCNC 2.9.9 or later, or backport the fix commits if you maintain a vendor fork.
For packaged installs, follow LinuxCNC’s documented update flow and prefer distro or project-supplied packages over ad-hoc source overlays.
If you need a short-term reduction while patching is in progress:
- Remove SUID or unnecessary elevated execution from
rtapi_appif your environment permits it. - Restrict shell access on LinuxCNC hosts to trusted operators.
- Treat any local-code-execution foothold on the host as potentially equivalent to root until the fix is installed.
Example mitigation if you have to reduce privilege exposure temporarily and have validated that your workflow tolerates it:
sudo chmod u-s "$(command -v rtapi_app)"
That is an operational workaround, not a universal fix. Test carefully because LinuxCNC environments may rely on the existing privilege model.
Response guidance
If an affected host may have exposed rtapi_app to untrusted local code, respond as a root-compromise scenario:
- rotate local secrets stored on the host
- inspect
/tmp, user home directories, and module search paths for suspicious.sofiles - review shell history and process-execution logs for unexpected
rtapi_appinvocations - validate system integrity before returning the controller or workstation to service
For defenders, this is a reminder that path traversal is not only a web vulnerability. When the sink is dlopen() inside a privileged Linux binary, a single unchecked module name is enough to turn “local user” into root.