Least Privilege Violation
Description
Least Privilege Violation is a vulnerability that occurs when a product operates with more privileges than necessary for the task at hand, particularly when elevated privileges required for specific operations like chroot() are retained after the operation completes. Programs that maintain unnecessary elevated privileges create security risks because any vulnerability discovered in the program can be exploited with those elevated privileges rather than being limited to the minimal access the program actually needs. This weakness represents a failure to follow the security principle of least privilege, which states that subjects should be granted only the minimum access necessary to accomplish their tasks.
Risk
Operating with excessive privileges significantly amplifies the impact of other vulnerabilities. When programs retain root or administrator access longer than necessary, buffer overflows, command injection, path traversal, and other exploits provide attackers with elevated access rather than limited user-level access. The risk compounds over time as the attack surface of privileged code is typically larger than necessary. Service accounts and daemons that run with elevated privileges throughout their lifetime present persistent high-value targets. Even temporary privilege retention creates windows of vulnerability during which exploits can achieve maximum impact. Organizations that fail to implement least privilege also face compliance issues with regulations like PCI DSS that mandate minimal access.
Solution
Drop elevated privileges immediately after completing operations that require them. Structure programs so that privilege-requiring operations occur at the beginning of execution, after which privileges can be permanently relinquished. Use capability-based security where supported to retain only specific required capabilities rather than full root access. Implement privilege separation architectures where a minimal privileged component performs only necessary elevated operations, communicating with unprivileged components that handle complex logic and untrusted input. Verify that privilege-dropping operations succeed by checking return values and confirming the resulting privilege state. Design systems with explicit trust zones and ensure sensitive data remains protected within appropriate boundaries. When elevated privileges cannot be avoided, minimize the code path that runs with those privileges and apply defense in depth.
Common Consequences
| Impact | Details |
|---|---|
| Access Control, Confidentiality | Scope: Access Control, Confidentiality Attackers exploiting any vulnerability in the program can access resources with elevated privileges that would not be accessible with the attacker's original or intended privilege level. This risk is amplified when combined with other vulnerabilities like buffer overflows, command injection, or code execution flaws. |
Example Code
Vulnerable Code (C)
The following examples demonstrate least privilege violations:
// Vulnerable: Retains root after privileged operation
#include <stdio.h>
#include <unistd.h>
int vulnerable_service(const char *app_home, const char *filename) {
// Perform privileged operation
chroot(app_home);
chdir("/");
// Vulnerable: Still running as root!
// All subsequent code runs with unnecessary privileges
FILE* data = fopen(filename, "r+");
if (data != NULL) {
// Vulnerability here (e.g., buffer overflow) = root compromise
process_user_data(data);
fclose(data);
}
// Long-running service loop - entire duration runs as root
while (1) {
handle_client_connection(); // Each client handled as root!
}
return 0;
}
// Vulnerable: Privilege only dropped temporarily
#include <unistd.h>
#include <sys/types.h>
void vulnerable_privilege_management(void) {
uid_t original_uid = getuid(); // Save original (likely non-root)
// Escalate to root
setuid(0);
// Do privileged operation
do_privileged_operation();
// Drop privilege
setuid(original_uid);
// Do unprivileged work
do_unprivileged_work();
// Vulnerable: Privilege can be regained!
// setuid only set effective UID, saved-set-uid is still 0
setuid(0); // This succeeds!
do_malicious_operation_as_root();
}
// Vulnerable: Java application with excessive permissions
public class VulnerableService {
public void processUserRequest(Request request) {
// Running with AllPermission in security manager
// or with unnecessarily broad file system access
// Every operation runs with maximum privileges
File userFile = new File(request.getFilePath());
// Vulnerability: Path traversal exploits full system access
readFile(userFile); // Can access ANY file on system
// Network operations also have excessive access
connectToServer(request.getServerUrl()); // No restrictions
}
}
Fixed Code (C)
// Fixed: Drop privileges immediately after privileged operations
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
int permanently_drop_privileges(const char *username) {
struct passwd *pw = getpwnam(username);
if (pw == NULL) {
return -1;
}
// Clear supplementary groups
if (setgroups(0, NULL) != 0) {
return -1;
}
// Set real, effective, AND saved group ID
if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
return -1;
}
// Set real, effective, AND saved user ID
if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
return -1;
}
// Verify we cannot regain privileges
if (setuid(0) != -1) {
return -1; // Should have failed!
}
return 0;
}
int secure_service(const char *app_home, const char *filename,
const char *run_as_user) {
// Perform privileged operation (requires root)
if (chroot(app_home) != 0) {
return -1;
}
if (chdir("/") != 0) {
return -1;
}
// IMMEDIATELY drop privileges after privileged operation
if (permanently_drop_privileges(run_as_user) != 0) {
fprintf(stderr, "Failed to drop privileges\n");
return -1;
}
// Now running as unprivileged user
// Any vulnerability is limited to that user's access
FILE* data = fopen(filename, "r+");
if (data != NULL) {
process_user_data(data); // Limited impact if exploited
fclose(data);
}
// Service loop runs unprivileged
while (1) {
handle_client_connection(); // Limited privileges
}
return 0;
}
// Fixed: Use capability-based security instead of full root
#include <sys/capability.h>
#include <sys/prctl.h>
int drop_to_capabilities(cap_value_t *needed_caps, int num_caps) {
cap_t caps;
// Create empty capability set
caps = cap_init();
if (caps == NULL) {
return -1;
}
// Add only required capabilities
if (cap_set_flag(caps, CAP_PERMITTED, num_caps, needed_caps, CAP_SET) != 0 ||
cap_set_flag(caps, CAP_EFFECTIVE, num_caps, needed_caps, CAP_SET) != 0) {
cap_free(caps);
return -1;
}
// Apply the restricted capability set
if (cap_set_proc(caps) != 0) {
cap_free(caps);
return -1;
}
cap_free(caps);
// Prevent further capability inheritance
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
return 0;
}
int secure_network_service(void) {
// Bind to privileged port (requires CAP_NET_BIND_SERVICE)
int sock = socket(AF_INET, SOCK_STREAM, 0);
bind_to_port(sock, 443);
// Drop to minimal capabilities
cap_value_t minimal_caps[] = {CAP_NET_BIND_SERVICE};
if (drop_to_capabilities(minimal_caps, 1) != 0) {
return -1;
}
// Service runs with only network capability, no other root powers
while (1) {
handle_connection(sock);
}
}
// Fixed: Java application with restricted permissions
public class SecureService {
private static final Set<String> ALLOWED_DIRECTORIES =
Set.of("/app/data", "/app/uploads", "/app/logs");
public void processUserRequest(Request request) {
// Validate and restrict file access
File userFile = new File(request.getFilePath());
if (!isPathAllowed(userFile)) {
throw new SecurityException("Access denied: " + userFile);
}
// Use SecurityManager with restricted policy
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkRead(userFile.getAbsolutePath());
}
readFile(userFile);
// Validate and restrict network access
if (!isAllowedServer(request.getServerUrl())) {
throw new SecurityException("Connection not allowed");
}
connectToServer(request.getServerUrl());
}
private boolean isPathAllowed(File file) {
try {
String canonical = file.getCanonicalPath();
return ALLOWED_DIRECTORIES.stream()
.anyMatch(canonical::startsWith);
} catch (IOException e) {
return false;
}
}
}
The fix ensures privileges are dropped immediately after operations that require them and uses permanent drops (setresuid) to prevent privilege regain.
Exploited in the Wild
Daemon Service Exploits (Unix/Linux Systems, Ongoing)
Network daemons that retained root privileges while processing client requests have been repeatedly exploited. Buffer overflows and format string vulnerabilities in services like sendmail, BIND, and other root-running daemons provided attackers with complete system access.
Container Runtime Vulnerabilities (Container Platforms, 2019-Present)
Container runtimes running with elevated privileges have experienced vulnerabilities where container escape was possible because the runtime maintained more privileges than necessary. CVE-2019-5736 demonstrated how retained privileges in container runtimes could be exploited.
Web Server CGI Exploits (Web Servers, Historical)
Web servers running CGI scripts with excessive privileges allowed web application vulnerabilities to compromise entire systems. Scripts running as root or with broad filesystem access turned simple web vulnerabilities into complete system compromises.
Tools to Test/Exploit
-
Lynis — Security auditing tool that identifies processes running with excessive privileges.
-
pscap — Tool to display capabilities of running processes, identifying privilege configurations.
-
grsecurity — Linux kernel security patches that include RBAC and capability-based security tools.
CVE Examples
Least privilege violations are typically contributing factors rather than standalone CVEs. They amplify the impact of other vulnerabilities:
-
CVE-2019-5736 — runc container escape exploited privileges retained by container runtime.
-
CVE-2021-4034 — Polkit pkexec local privilege escalation exploited suid-root execution.
-
CVE-2021-3156 — Sudo heap overflow escalated to root due to setuid privileges.
References
-
MITRE Corporation. "CWE-272: Least Privilege Violation." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/272.html
-
CERT C Secure Coding Standard. "POS02-C. Follow the principle of least privilege." https://wiki.sei.cmu.edu/confluence/display/c/POS02-C
-
CERT Oracle Secure Coding Standard for Java. "SEC00-J. Do not allow privileged blocks to leak sensitive information." https://wiki.sei.cmu.edu/confluence/display/java/SEC00-J
-
Saltzer, J.H. and Schroeder, M.D. "The Protection of Information in Computer Systems." IEEE. https://ieeexplore.ieee.org/document/1451869