What Is Privilege Escalation? Types, Examples & Prevention in Web Applications
Privilege escalation (PrivEsc) is one of the most critical vulnerabilities in web applications. This guide explains horizontal vs. vertical privilege escalation, real-world attack techniques like parameter manipulation, SQL injection, and insecure file uploads, and the access control failures that enable them — plus how to prevent them.
What is Privilege Escalation?
Privilege escalation is an attack where the adversary changes their provisioned set of permissions. Privilege escalation, or PrivEsc as penetration testers like to call it, is probably every hacker's goal. If they are lucky, they can go from unauthenticated web user to server admin and gain root server access in one attack. More often than not, it might require the attacker several steps to reach that goal. For example, from an unauthenticated user to an authenticated user, then to a privileged user, then to a footprint on the server, from which they escalate their attack to admin/root on the server.
Privilege Escalation is a symptom of weak, ineffective, or incomplete access controls. In most cases, PrivEsc exists because of weak or missing security controls.
Access control is the combination of:
- Authentication: proper identification of the user’s identity, basically ensuring the user is who they say they are
- Session management: the process of tokenizing this identity into the user’s session, so the application does not have to check the identity on every request
- Authorization enforcement: the process of ensuring that the user has access to the resources they claim they have access to.
With that in mind, the process of privilege escalation is when the attacker tries to circumvent one or more of these access controls (i.e., authentication, session management, and/or authorization) to exploit a privilege escalation vulnerability.
How is Privilege Escalation in Web Applications Different
The main difference between privilege escalation in web/API applications and in networks is the attack surface. The attack surface is much larger and more complex in web and API applications than in networks.
Every single server URL, file, API endpoint, and accepted HTTP Verb (e.g., GET, POST, DELETE, etc.) is a potential target for a privilege escalation attack.
There are two main types of privilege escalation.
Horizontal Privilege Escalation:
In this type of privilege escalation, the attacker is trying to move laterally to gain access to unauthorized data or privileges. For example, in a banking application, an attacker might try to gain access to someone else’s account; in this case, the attacker is not trying to get admin access (i.e., move up) but lateral access (i.e., move sideways). Another example: in a multi-tenant environment, the attacker is trying to gain access to the resources and data of another tenant.
Vertical Privilege Escalation:
In this type of privilege escalation, the attacker is trying to move vertically and expand their set of permissions. For example, an attacker with no access at all (i.e., unauthenticated), who is trying to get authenticated-user privileges. Another example is an authenticated user who is trying to elevate their privileges and gain access to the set of permissions an administrator would have.
The ultimate form of privilege escalation is when the attacker gains admin (i.e., root) access to the server. Whether horizontal or vertical privilege escalation, this could be achieved using one or more of the following hacking techniques:
1- Parameter Manipulation:
Parameter manipulation is an attack where, through the manipulation of an HTTP request parameter, the attacker can exploit the server-side protection, or the lack of it, to gain unauthorized access to a resource or a database record by simply modifying a parameter in the HTTP QueryString or body. Take, for example, the following.
GET /retrieveaccount?accountID=12345 HTTP/1.1
Host: vulnsaas.com
Accept: */*
Content-Length: 0
Changing the account ID to, let’s say, 12456 might lead to retrieving someone else’s account information.
2- Lack of server-side security controls
There is a lot of variety in this particular vulnerability. For example, let’s assume the following web application, where an admin has access to a menu with five functionalities (Tasks, Documents, Files, Discussions, and Settings)

Clicking each menu item would trigger a request to the prospective API endpoint; for example, “Tasks” would issue a request to “/api/v2/tasks,” and so on.
Not, let’s assume a regular user does not have access to the last two menu items. They have access only to: “Tasks”, “Documents”, and “File.s”

In this case, the user does not have access to “Discussions” or “Settings” from the menu. But the lack of server-side security controls does not prevent them from sending the request directly to those API endpoints.
There are several other scenarios of a lack of server-side security controls; for example, let’s assume a regular user in the previous example has access to their own documents, but an Admin has access to everyone’s documents.
So the request might look something like:
GET /api/v2/documents/user HTTP/1.1
Host: vulnsaas.com
Accept: */*
Content-Length: 0
Changing the URL to something like this:
POST /api/v2/documents/all HTTP/1.1
Host: vulnsaas.com
Accept: */*
Content-Length: 0
This would give the user access to all documents due to the lack of server-side controls that verify the user actually has access to all files.
3- Command Injection
Command Injection is a vulnerability that would allow an attacker to execute commands directly on the server side. In this case, the attacker is looking to elevate their privileges from a web user, whether authenticated or not, to obtain a shell on the server, and may be able to elevate their privileges to root in some cases.
Take, for example, this piece of code:
String comm = "cmd.exe /c dir "+ request.getParameter(“file”);
Process process = Runtime.getRuntime().exec(comm);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(process.getInputStream()));
Passing the following URL http://vulnsaas.com?file=.;ipconfig -a would execute the following commands respectively.
cmd.exe /c dir.
Ipconfig -a
4- SQL Injection:
SQL Injection is a vulnerability that allows attackers to manipulate SQL queries within the application. This would allow the attacker to, in addition to other things, run their own queries to retrieve data they are not authorized to access. But SQL injection could also be used to escalate privileges. Most database management systems have a functionality to run system commands as part of a query. In this case, the attacker is trying to elevate their privileges from a web user to a console/server user, and ultimately server root/admin. For example, SQL Server has xp_cmdshell:
EXEC xp_cmdshell 'dir *.exe';
GO
Here is another super long way to do the same thing in Postgres
CREATE TABLE trigger_test
(
tt_id SERIAL PRIMARY KEY,
command_output TEXT
);CREATE
OR
replace FUNCTION trigger_test_execute_command()
returns TRIGGER language plpgsql AS $body$
BEGIN
copy trigger_test (command_output) FROM program 'echo 123';RETURN NULL;END;$BODY$;CREATE TABLE trigger_test_source
(
s_id INTEGER PRIMARY KEY
);CREATE TRIGGER tr_trigger_test_execute_command after
INSERT
ON trigger_test_source FOR each statement
EXECUTE PROCEDURE
trigger_test_execute_command();
insert INTO trigger_test_source VALUES
(
2
);
table trigger_test;
tt_id │ command_output ───────┼──────────────── 1 │ 123
Thankfully, most database management systems come with this functionality disabled by default. However, there is always a way to enable it.
5- Insecure File Upload
One of the most underestimated vulnerabilities out there. Although it is seen less in the wild right now, the existence of this vulnerability could lead to a straight-up, complete server takeover. Take this StackOverflow answer, which was marked as the right answer for the question: “Upload a file using PHP”.
<?php
$target_dir = "upload/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = pathinfo($target_file, PATHINFO_EXTENSION);
// Check if image file is a actual image or fake image
if (isset($_POST["submit"])) {
if ($target_file == "upload/") {
$msg = "cannot be empty";
$uploadOk = 0;
} // Check if file already exists
else if (file_exists($target_file)) {
$msg = "Sorry, file already exists.";
$uploadOk = 0;
} // Check file size
else if ($_FILES["fileToUpload"]["size"] > 5000000) {
$msg = "Sorry, your file is too large.";
$uploadOk = 0;
} // Check if $uploadOk is set to 0 by an error
else if ($uploadOk == 0) {
$msg = "Sorry, your file was not uploaded.";
// if everything is ok, try to upload file
} else {
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
$msg = "The file " . basename($_FILES["fileToUpload"]["name"]) . " has been uploaded.";
}
}
}
?>
The code is validating whether a file is actually being uploaded, but there is much more to ensure the upload is secure. The code is not validating the file's content or its extension. The most dangerous part is that the file is being uploaded to the server with its original name. If that location is web-accessible, that’s all the attacker needs. In this case, the attacker will upload a PHP file, and, assuming it is web accessible, they can simply execute whatever malicious code is in it.
Privilege Escalation Mitigations:
Privilege escalation is every attacker's goal, so they naturally look for it aggressively. Privilege escalation is a vulnerability that can definitely get your company in the news or put you in an embarrassing situation with a client. P
- Strong Authentication Controls: It goes without saying that strong authentication controls are super important to ensure the identity of every request. Every endpoint, serve file, API, and HTTP Method should all be protected.
- Strong Access Control: similar to authentication, strong access controls should protect every endpoint. Access control is much harder to get right than authentication, especially for applications with multiple roles and configurable permissions.
- Avoid calling system commands from source code: unless necessary, system commands shouldn’t be called from source call at all. If necessary, then a very strong “Allow List” should be implemented.
- Use ORMs or Parameterized statements: these are very important, not just to stop privilege escalation but to stop SQL injection as well.
- Hardening your whole stack: laxed or insecure configuration could also lead to privilege escalation.
- Penetration Testing: Implementing all the above is not a guarantee that your application is PrivEsc-less. Keep in mind that you need to close all the gaps, while the attacker is only looking for one to exploit. Penetration testing is the best way to ensure that all the mitigations mentioned above are strong enough and implemented across the board.
References:
https://dba.stackexchange.com/questions/128229/execute-system-commands-in-postgresql
https://www.stackhawk.com/blog/command-injection-java/#:~:text=command%20injection%20vulnerabilities.-,What%20Is%20Command%20Injection%3F,is%20part%20of%20these%20commands.
.avif)


