Saving CSRF – Client-Side Path Traversal to the Rescue
For quite some time now, we’ve seen a clear trend towards using a lot of client-side code with frameworks like React, Angular, Vue.js, NextJS, Vue, and others. Instead of relying heavily on the server, much of the logic and code now runs directly in the browser. This shift can make apps feel faster and more responsive, but it also opens the door to other security risks.
As more logic shifts to the client-side, the focus on security needs to shift as well. With more JavaScript code running in the browser, it’s crucial to pay closer attention to client-side vulnerabilities as there’s a greater opportunity for attackers to review the application source code and take advantage of any weaknesses.
Cross-Site Request Forgery
One of the well-known security issues that has been a major concern for years is Cross-Site Request Forgery (CSRF). Over the years, various protections have been implemented by browsers to mitigate CSRF attacks such as SameSite cookies and improved HTTP header-based controls. These measures have made CSRF attacks less prevalent, but they haven’t eliminated them completely.
Client-Side Path Traversal
While path traversal allows attackers to manipulate file paths to access restricted files on a server, client-side path traversal targets the client-side code, redirecting requests to unintended API endpoints or triggering unauthorized actions.
It’s worth noting that CSPT attacks can have a wide range of impacts depending on the context and can be used in various attack chains beyond just CSRF. In this post, we’ll focus on how a CSPT vulnerability can be exploited to carry out a CSRF attack.
Rules are Made to be Broken
“Redirecting requests to unintended API endpoints or triggering unauthorized actions.”
Uhm, that’s interesting, right?
CSRF is typically mitigated by adding a pseudorandom, unpredictable request parameter which prevents unintended requests that are made by malicious actors on behalf of authenticated users, or by altering default browser behavior to block the inclusion of HTTP cookies in cross-site requests. However, when abusing a client-side path traversal, the vulnerability lies within the JavaScript code itself. This allows an attacker to trigger requests to arbitrary application endpoints by manipulating the input parameters of the JavaScript code. Unlike traditional CSRF, the existing anti-CSRF mechanisms are not sufficient to protect web applications from these attacks.
When exploring CSPT, it’s important to know that not all potentially vulnerable user input sources need to exist within the front-end code. Almost any user input can lead to CSPT, including HTTP request elements, such as:
- Query parameters
- Path parameters
- URL Fragments
The complexity and severity depend on whether additional actions are required to trigger the vulnerability and the limitations imposed by the source, such as restricted control over HTTP methods, headers, and body content.
Practical Example
I’ve created a little example to show how a client-side path traversal can be used to achieve a CSRF.
In this example, we have a website that simulates a “Manage Preferences” page, where users can remove items like “favorites” and “notifications.” Upon inspecting the code, you can see that a fetch request is made to a specific API endpoint to handle these actions. The setting ID is passed as a query string parameter (id), and this value is then used in the fetch request to call the API and remove the selected setting.
Everything seems fine so far, right? Well, not quite.
What if an attacker manipulates the id parameter by adding something like “../../../../” to the path? This could redirect the DELETE request to a different endpoint altogether. This means that an attacker could potentially control where the request is sent. Now, imagine there’s an endpoint that performs a more critical action, like disabling Multi-Factor Authentication (MFA). If this endpoint uses the same HTTP method, the attacker might be able to exploit it.
In our scenario, the attacker knows that there are other API endpoints, including those related to admin actions, such as an endpoint for disabling MFA. So, they craft a new payload to target the “admin/settings/mfa” endpoint. But there’s a problem: the DELETE request ends up at “admin/settings/mfa/disable” because the original endpoint includes the word “disable” in its path (see fetch request).
Is this a dead end? Not quite.
By using a simple trick — adding the “#” character (encoded as %23 in the URL) — the attacker can truncate the URL, removing everything that comes after the “#”. This allows them to remove the unwanted part of the endpoint and successfully exploit the vulnerability.
Final PoC:
http://127.0.0.1:5000/preferences/edit-preferences?id=a5ed31dc-408f-43a5-8e8c-8a4ce05cf588../../../../admin/settings/mfa%23
If an attacker sends this hyperlink to a victim and they click on it, a DELETE request will be automatically sent to the MFA endpoint. But what about the CSRF token? It doesn’t matter in this case because, as mentioned, the fetch request automatically includes the CSRF token, allowing the attack to succeed.
Conclusion
Client-side path traversal vulnerabilities shouldn’t be overlooked as they are very dangerous, especially when they lead to unintended actions like CSRF attacks. It is important to review how input parameters are handled in client-side code. By understanding how these types of vulnerabilities work and how they can be exploited, developers and security researchers can better protect their applications.
Resources and References:
Written By:
Leonel Algare is a Sr. Offensive Security Consultant at Netragard. Leo is currently leading projects that involve testing web applications, infrastructure (internal/external), mobile applications, and social engineering activities.
With over 10 years of professional experience in cybersecurity he has worked in different industries such as…>>Read Bio