A service may need to execute helper programs after it has accepted untrusted input. If one of those programs is set-user-ID, set-group-ID, or carries file capabilities, a normal execve() can cross a privilege boundary even when the calling process itself has no intent to acquire extra authority. Linux no_new_privs changes that transition: once set for a thread, later execve() calls cannot grant privileges that were absent from the caller at the point of execution.
The property is deliberately narrow. It constrains privilege gain across program execution; it does not remove authority the process already possesses. That distinction makes no_new_privs useful as a one-way execution boundary, but insufficient as a complete sandbox.
The bit is a one-way process attribute
A thread sets the attribute with prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0). After a successful call, the value cannot be cleared. Child processes created by fork() and clone() inherit it, and execve() preserves it.
This one-way behavior matters because a process can establish the boundary before handing control to less trusted code. That code cannot later clear the bit and execute a privileged binary to recover an exec-time elevation path.
The setting is per thread in the kernel interface. In a multithreaded program, code must account for which threads have set the attribute and which execution paths can create descendants. Treating it as an automatically process-wide switch can leave a different thread outside the intended boundary.
execve suppresses three common elevation mechanisms
When no_new_privs is active, execve() does not honor the set-user-ID and set-group-ID mode bits as mechanisms for increasing privilege. File capabilities are likewise prevented from adding privilege during the execution transition.
The resulting behavior is not equivalent to pretending those filesystem properties do not exist. The kernel still performs an execution transition under its normal credential rules, but the transition is constrained so that the new program cannot become more privileged through those mechanisms.
This also affects Linux Security Module processing. The kernel contract prevents an execve() from using an LSM transition to relax restrictions that apply to the caller. Security modules retain their own semantics, so deployment policy still determines the exact labels and checks involved.
A practical consequence is that a helper designed to become privileged only because its executable has a set-user-ID bit can execute without receiving that elevation. Software that assumes the helper will always obtain its privileged identity can therefore fail after the boundary is enabled.
Existing authority survives the transition
The name can suggest a broader reduction than the kernel provides. no_new_privs does not revoke open file descriptors, mapped memory, credentials, namespaces, network access, or other resources already available to the process. It also does not itself remove capabilities already present in the relevant credential sets.
A process that starts with dangerous authority can retain dangerous authority after setting the bit. The mechanism only blocks additional privilege arising from execve() paths covered by its contract.
This separates two security operations that are often combined in sandbox setup. Privilege dropping reduces authority already held. no_new_privs prevents selected execution transitions from adding authority later. A robust confinement design may require both, plus controls over filesystem, network, system calls, and inherited descriptors.
Seccomp uses the boundary for unprivileged filter installation
Linux seccomp filter installation has a direct relationship with no_new_privs. A thread without CAP_SYS_ADMIN in its user namespace must have no_new_privs set before it can install a seccomp filter with SECCOMP_SET_MODE_FILTER; otherwise the operation fails.
The requirement prevents an unprivileged process from installing a filter and then executing a set-user-ID program that would inherit the filter under a newly privileged identity. Without an exec-time privilege barrier, syscall filtering could become a tool for altering the behavior of a privileged program in an attacker-controlled way.
The relationship does not make the two mechanisms interchangeable. Seccomp restricts the system-call interface according to its filter semantics. no_new_privs constrains privilege acquisition across execution. Setting one does not reproduce the enforcement surface of the other.
The boundary does not make execution harmless
An executable can still be malicious or unsafe without gaining a new UID, GID, or capability. It can act with the caller’s existing permissions, consume inherited file descriptors, modify writable files, communicate over available sockets, or exploit authority exposed by the surrounding process environment.
The setting also does not validate the executable’s origin or integrity. Path resolution, filesystem permissions, mount configuration, signatures, and content-integrity mechanisms remain separate concerns.
For service launchers and sandbox runtimes, the useful property is compositional: after the bit is set on the relevant execution path, later program execution cannot use the covered exec-time mechanisms to step above the caller’s privilege state. Other controls can then narrow the authority that remains.
Placement determines the effective trust boundary
The strongest operational pattern is to set no_new_privs after any intentionally privileged setup is complete and before control reaches code that must never regain privilege through execution. Setting it too early can break a legitimate helper that still needs an exec-time credential transition. Setting it too late leaves earlier execution paths capable of crossing that boundary.
Because the attribute is irreversible, its placement is an architectural decision rather than a temporary toggle. The process tree below that point inherits a durable restriction, making the location of the call part of the application’s trust-boundary design.
no_new_privs is therefore most precise when treated as an exec-time privilege ceiling. It does not define the whole sandbox, but it closes a specific class of privilege transitions in a form that descendants cannot opt out of.