According to the principle of least privilege, code should not be granted more privileges than those required for performing the particular task. This means that sections of code that require elevated privileges should be kept to a minimum. McGraw and Felten [[McGraw 00]] enlist various goals of the principle of least privilege in the context of the Java programming language:
- We want to grant each applet or application the minimum privileges it needs.
 - Rather than assigning a given applet's entire collection of privileges to all of its classes, we want each class to get just what it needs.
 - We want a class's privileges to be "turned off" except for brief periods of time.
 - We even want to reduce the privileges of some of the built-in system classes.
 
The ways in which these goals can be achieved are discussed below.
An applet can be granted the minimum set of privileges by leaving it unsigned, however, this is not possible if it is designed to perform privileged operations (ENV00-J. Do not sign code that performs only unprivileged operations). For applications, some additional steps may be required depending on the security policy. The default security policy file is quite restrictive in granting permissions. However, the flexible security model allows the user to grant additional permissions to applications by using a custom security policy. Several guidelines deal with granting or limiting permissions (for instance, ENV00-J. Do not sign code that performs only unprivileged operations, ENV31-J. Never grant AllPermission to untrusted code, ENV32-J. Do not grant ReflectPermission with target suppressAccessChecks and ENV33-J. Do not grant RuntimePermission with target createClassLoader).
There are several ways to practice privilege separation. Applets or applications that need to be signed can coexist with unsigned classes in the same package (or JAR file). It is recommended that all privileged code be packaged together (ENV01-J. Place all privileged code in a single package and seal the package). Furthermore, it is possible to grant privileges to code on the basis of the code base or its signer using a security policy.
The third goal can be realized using the AccessController mechanism. This mechanism allows only certain parts of code to acquire elevated privileges. When a class needs to enable its own privileges, it executes the sensitive privileged code in a doPrivileged block. Also, recall that the AccessController mechanism works in conjunction with the security policy in effect. From the viewpoint of users, most often they do not understand complex security policies or code signing. They cannot be relied upon to restrict permissions appropriately in non-default security policy files. Consequently, privileged code must be written with utmost care assuming that the user is incapable of correctly configuring the security policy. For example, doPrivileged blocks should not create and use temporary files in shared directories because this is considered unsafe on some platforms (FIO34-J. Do not create temporary files in shared directories).
The fourth goal can be achieved by using a security manager or AccessController mechanism to control what functions the trusted Java API can perform (ENVxx-J. Create a secure sandbox using a Security Manager). Sometimes untrusted code should not be allowed to access system classes. This is achieved by granting code specific permissions and protecting it from accessing trusted classes in the specified packages. The accessClassInPackage permission provides the required functionality (SEC07-J. Do not grant untrusted code access to classes existing in forbidden packages). Doing so does not limit what system classes can do, however, it restricts the range of system packages that can be invoked from less-privileged code.
Noncompliant Code Example
This noncompliant code example includes unprivileged code following the privileged openPasswordFile statement in the doPrivileged block. This is a violation of the principle of least privilege. 
AccessController.doPrivileged(new PrivilegedAction() {
  public Object run() {
    try {
      f[0] = openPasswordFile(password_file);  // call the privileged method here
      // other operations, such as opening a temporary file in a shared directory 
    }catch(FileNotFoundException cnf) { 
      System.err.println("Error: Operation could not be performed");
    }
    return null;
  }
});
Compliant Solution
It is critical to reduce the amount of code that requires elevated privileges to a minimum. Privileged code must also be audited more carefully than unprivileged code. This is essential to prevent the misuse of privileges.
AccessController.doPrivileged(new PrivilegedAction() {
  public Object run() {
    try {
      f[0] = openPasswordFile(password_file);  // call the privileged method 
      // no unprivileged operations (including safe ones)
    }catch(FileNotFoundException cnf) { 
      System.err.println("Error: Operation could not be performed");
    }
    return null;
  }
});
// other operations 
In this compliant solution, any operations on the file descriptor f[0] must occur outside the privileged block. It is also critical to ensure that f[0] does not leak out to untrusted code ([SEC02-J. Guard doPrivileged blocks against untrusted invocations]). 
Noncompliant Code Example
Sometimes code needs to take into account the privileges of another context while performing a security critical action. If such code is granted the privileges of the current execution context (snapshot of the current thread), a vulnerability is exposed. This noncompliant code example shows a library method that allows all callers to perform a privileged operation (such as a read or write to a file) by using the wrapper method performActionOnFile(). The corresponding code is granted the permissions to both read and write the file. However, the caller only desires read access to the file to prevent any misuse. This code violates the principle of least privilege by also providing the caller with write access. 
private void openFile() {
  final FileInputStream f[] = {null};
 
  AccessController.doPrivileged(new PrivilegedAction() {
    public Object run() {
      try {
        f[0] = new FileInputStream("file"); 
      } catch(FileNotFoundException cnf) { 
        System.err.println("Error: Operation could not be performed");
      }
      return null;
    }
  });
}
// wrapper method
public void performActionOnFile() {
  openFile();	
}
Compliant Solution
The two argument form of doPrivileged() accepts an AccessControlContext object from the caller and restricts the privileges of the contained code to the intersection of the permissions of the current execution context's domains and those of the context passed as the second argument. Consequently, a caller that requires only read permission to the file can pass a context that has only the file read permission. 
private void openFile(AccessControlContext context) {
  final FileInputStream f[] = {null};
  AccessController.doPrivileged(new PrivilegedAction() {
    public Object run() {
      try {
	f[0] = new FileInputStream("file"); 
      } catch(FileNotFoundException cnf) { 
	System.err.println("Error: Operation could not be performed");
      }
      return null;
    }
  },context); // restrict the privileges by passing the context argument
}
// wrapper method
public void performActionOnFile(AccessControlContext acc) { 
  openFile(acc); // caller's AccessControlContext	
}
In this case, the two-argument form is preferable because the openFile() method does not know whether the caller should be granted the read, the write or both permissions. Prefer the single argument AccessController.checkPermission(permission) method when the permissions of the caller are known a priori.
The performActionOnFile() method need not be declared private if permissions are restricted by accepting a context argument. Refer to the compliant solution of SER37-J. Do not deserialize from a privileged context for more details on creating protection domains with specific permissions.
Risk Assessment
Failure to follow the principle of least privilege can lead to privilege escalation attacks when a vulnerability is exploited.
Rule  | 
Severity  | 
Likelihood  | 
Remediation Cost  | 
Priority  | 
Level  | 
|---|---|---|---|---|---|
SEC00- J  | 
high  | 
probable  | 
high  | 
P6  | 
L2  | 
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
[[API 06]] Class java.security.AccessController
[[McGraw 00]]
[[MITRE 09]] CWE 272![]()
02. Platform Security (SEC) 02. Platform Security (SEC) SEC01-J. Provide sensitive mutable classes with unmodifiable wrappers