Introduction

Welcome to the fourth lesson of the "broken access control" course! In this lesson, we will explore the concept of privilege escalation, a critical aspect of broken access control vulnerabilities.

By understanding how attackers can exploit these vulnerabilities to gain unauthorized access to higher-level privileges, you'll be better equipped to secure your applications. Let's dive in and learn how to prevent privilege escalation! 🚀

Understanding Privilege Escalation

Privilege escalation occurs when an attacker gains elevated access to resources that are normally protected from an application or user. There are two main types: vertical privilege escalation and horizontal privilege escalation. Vertical privilege escalation involves gaining higher-level privileges, such as administrative rights, while horizontal privilege escalation involves accessing the resources of another user with similar privileges.

For example, if a regular user can change their role to an admin by manipulating a request, that is vertical privilege escalation. On the other hand, if a user can view another user's private data without permission, that is horizontal privilege escalation. Understanding these concepts is vital for securing web applications against unauthorized access.

Let's look at a vulnerable code example to see how these vulnerabilities can manifest in real applications.

Vulnerable Code Example

Let's examine a code snippet that demonstrates a vulnerability allowing privilege escalation. This example shows how a lack of proper validation can lead to unauthorized role changes.

In this code, any authenticated user can update their profile, including the role field, without any authorization checks. An attacker could send a payload to change their to , leading to . This vulnerability arises from the absence of . To understand the severity of this issue, let's see how an attacker might exploit this vulnerability.

Exploiting the Vulnerability

To understand the impact of the vulnerability, let's see how it can be exploited. An attacker could use a simple script to change their role to admin.

This command sends a curl request to update the user's role to admin. Without proper authorization checks, the application accepts this change, granting the attacker unauthorized admin access. This highlights the importance of securing code against such exploits. Let's start fixing these vulnerabilities by understanding our JWT authentication setup.

JWT Authentication Recap

As we learned in Lesson 2, we are using JWT authentication with a custom JwtUtil class. When a request is authenticated, we extract the user's information from the JWT token. We retrieve the authenticated user's information using our getCurrentUser helper method:

This authentication mechanism ensures that every request to protected endpoints includes a valid JWT token, and the user's identity is securely retrieved from the database. With this in place, we can now use the authenticated user's information to implement proper authorization checks.

Authentication and Identity Verification

With JWT authentication in place, our updateUser endpoint already uses the user's identity from the JWT token. The getCurrentUser method extracts the userId from the token and retrieves the user from the database:

This ensures that users can only update their own profiles, as the identity comes directly from their authenticated token. Importantly, this approach automatically protects against horizontal privilege escalation - User A cannot update User B's profile because the userId is always extracted from the authenticated user's JWT token, not from the request parameters. However, we still need to restrict what fields they can update based on their role to prevent vertical privilege escalation.

Restricting Field Updates

To prevent privilege escalation, we need to restrict non-admin users from updating sensitive fields like role. We can check the user's role from the database and only allow updates to safe fields:

This code allows non-admin users to update only basic fields (username and password), preventing unauthorized role changes. Notice how we use a UpdateUserRequest data transfer object (DTO) instead of accepting the full User entity in the request body. This provides an additional layer of protection by explicitly defining which fields can be submitted.

Now, let's implement special handling for admin updates to maintain necessary flexibility for system administrators.

Allowing Admin Updates

For administrative users, we can allow full access to update all fields:

admins have the authority to update any field, including the role, ensuring flexibility while maintaining security. Note that this implementation allows an admin to change their own role to user. While not a security vulnerability, this is a common logic bug that can lead to "admin lockout" - where the last admin accidentally removes their own permissions, leaving the system without administrative access. In production systems, you might want to add additional checks to prevent the last admin from demoting themselves or require a separate privileged operation for role changes. This completes our secure implementation of user profile updates.

Conclusion and Next Steps

In this lesson, we explored the concept of privilege escalation and how it can be exploited through vulnerabilities in web applications. We examined a vulnerable code example and demonstrated how it can be exploited. By implementing secure coding practices, such as JWT authentication, role-based access control (RBAC), and proper validation, we can prevent privilege escalation and protect our applications.

As you move on to the practice exercises, apply what you've learned to identify and fix privilege escalation vulnerabilities. This hands-on experience will reinforce your understanding and prepare you for more advanced security challenges. Keep exploring and stay secure! 🔒

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal