Threat Research API: Server-Side Request Forgery on FinTech Platform Enabled Administrative Account Takeover


Synopsis of the incident

The Salt Labs team helps customers and prospects discover vulnerabilities in their APIs. In this case, we investigated the platforms of a large US-based FinTech company. This company offers a “digital transformation” service for banks of all sizes, allowing them to switch many of their traditional banking services to online services. The platform is already actively integrated into the systems of many banks, and its services are used by millions of people daily.

Following the API vulnerabilities identified by our researchers, they were able to launch attacks where:

  • Attackers could gain administrative access to the banking system using this platform
  • Attackers could leak users’ personal data
  • Attackers could gain access to users’ bank details and financial transactions
  • Attackers could make unauthorized fund transfers to their own bank accounts

Platforms such as this are considered prime targets for attackers looking to exploit API vulnerabilities. Why? Two main reasons. First, their API landscape and overall functionality is very rich and complex, which leaves a lot of room for errors or missing details in development. Second, if a bad actor can successfully abuse this type of platform, the potential profits are enormous, as it could allow control of the bank accounts and funds of millions of users.

As with many faulty API implementations, a number of issues that allow services to be exploited match the OWASP API Security Top 10, including:

Maintaining the anonymity of this service provider is essential, so we have sanitized all technical details that could identify the organization. After identifying the vulnerability, we reviewed our findings and provided recommended mitigations to the organization. As part of Salt Labs’ broader mission, here we share findings to increase awareness of API vulnerabilities, including explaining the attack pattern, detailing attack propagation steps, and highlighting highlight mitigation techniques.

Our research approach

As Salt Labs researchers engage in such an environment, the first observation is that we are dealing with a huge ecosystem. The FinTech company provides digital services to numerous banks and credit unions, each with their own website, mobile app, custom integrations, webhooks, and more. Our first and most important task in finding critical API issues: Focus.

Using our years of experience studying real-world API issues, we’ve developed a form of “sixth sense” that allows us to flag potential places within this ecosystem that might be more error-prone. than others and in which our chances of finding critical API bugs in a relatively short time are considerably higher.

In this specific case, we focused on external interactions. Specifically, we focused our efforts on two major parts of one of the bank’s websites: webhooks and third-party integrations. Any banking site should have such built-in features, as they usually allow functions like advanced notification options, funds transfer, etc.

Incident details

Our initial strategy in such cases would simply be to scan relevant regions of the website while logging all traffic sent and received. Later, we can take a closer look at the traffic to identify places that may have bugs. During one of our first analyses, we came across this service:

This page of the FinTech company site supports the fund transfer functionality of the platform. It does exactly what you expect it to do – lets you transfer funds to an external bank. The user can choose the bank to transfer the funds to and fill in all the necessary details – then the funds are transferred.

The functionality is simple for the customer, but what does it look like behind the scenes? Let’s look at the actual traffic sent once the funds have been transferred.

No surprise – the web browser calls an API to handle this request. This specific API uses the endpoint located at “/workflows/tasks/{TASK_GUID}/values”, the HTTP method used to call it is PUT, and the specific request data is sent in the HTTP body section.

Another interesting aspect to note is that the request body carries a JWT Bearer token. A JWT token, in case you don’t know it, is a cryptographically signed key that lets the server know who the requesting user is and what permissions they have.

Up to this point, everything seems ok. This is a valid request, and it carries a legitimate and secure authentication token. But now, let’s take a closer look at the demand data itself.

The request parameters include, as it should, the data required for this transfer of funds. But for any of you who’ve ever struggled with web security, one setting immediately stands out: InstitutionUrl.

“InstitutionUrl” is a user-supplied value that includes a URL pointing to a GUID value placed on the receiving bank’s website. It is not important at this time to understand what this GUID value means or how it is used. The most interesting part to understand is this: how does our bank’s web server handle a user-provided URL? Is the platform trying to contact this URL itself? What happens if a user inserts an arbitrary URL, such as Will the web server still try to reach it? If so, it would be a potentially very critical security issue – a server-side request forgery (SSRF).

How can we determine if the server is actually contacting an arbitrary domain provided by the user? Easy – we’ll just provide our own URL. Of course, the transfer of funds will most likely fail, but by listening to incoming traffic on our own URL, we will be able to verify this point and further inspect the received traffic.

We go ahead with the plan – we forge a malformed request containing our own domain, cross our fingers and wait. A few seconds later… Bingo! We have an incoming connection to our server. Seeing this traffic validates our suspicions and means that the server blindly trusts the domains provided to it in this parameter and sends a request to this URL.

Let’s inspect this new request arriving on our server:

The request itself seems rather useless and doesn’t contain much information to use. However, like our original request to the API endpoint, it also contains a JWT token used for authentication. Since JWT tokens contain simply encoded (and signed) text fields, we can very easily inspect its contents. Looking inside you see:

Wow – it looks like the server request contains a different JWT token than the original one, and this token contains a scope called “service-request/request”, also different from the JWT of the original request. It seems that this new token does not contain any group restrictions.

At this point we are wondering how we can use this new JWT token with the website. Scraping our memory (and our research notes), we tried to embed this new JWT token into a request we had previously encountered. This API request was sent to an endpoint named “/accounts/account”. When used with the original JWT token, this request simply returned our account information. What will it return if we use our new JWT token?

Surprising! The API endpoint recognized our new JWT admin token and very gracefully returned a list of each user and their platform details.

This reveal is bad enough, but we wanted to see how far this rabbit hole would go. So we made another request to a different API endpoint. This time we used the “/transactions/transactions” endpoint. Can you guess what we got in response?

Yes. A list of all transactions performed by each user on the banking system.

This vulnerability is a critical flaw, which completely compromises every bank user. Had bad actors discovered this vulnerability, they could have caused severe damage to both the FinTech company and its users. At a minimum, an attacker could have disclosed all personal data of platform users and all their banking transactions. For reasons of business ethics, we have not pursued further research efforts, but are confident that the potential damages would have been much greater, potentially allowing manipulation of user funds and possibly even draining accounts of all their funds.

Lessons learned

As we always do, we have followed coordinated disclosure practices and are pleased to report that all issues we discovered have now been resolved.

How can other companies prevent such a potential catastrophe? User-controlled input is the big culprit. One should never blindly rely on such parameters. Software and API developers should always make sure to apply as many protections as possible to any user input, especially if the input values ​​are susceptible to attacks such as URL values ​​that can lead to SSRF or other vulnerability classes.

In our opinion, the most effective protection would be a combination of static protections – such as basic sanitization or whitelisting – combined with runtime protections that identify anomalies in API traffic. Such protections would be able to fill in the gaps or workarounds made to static methods.

This threat research describes the risks and potential harms that come with every API implementation. The most disturbing aspect of this situation is that the entire attack – all of our research – went completely unnoticed by the bank. The FinTech company used traditional WAF solutions to protect its sites, and these devices unfortunately cannot detect the subtle manipulations characteristic of API attacks.

This FinTech company is by no means the only one. At Salt Labs, we see vulnerabilities like this and other API-related issues daily. We will continue to highlight these findings to promote awareness of API security, as the consequences of such flaws can be severe, and we strongly believe that education is fundamental to finding and resolving these issues.

Stay tuned for more research on API issues in the trenches in the near future. And until then, protect yourself!


*** This is a Security Bloggers Network syndicated blog from the Salt Security blog written by Salt Labs. Read the original post at:


About Author

Comments are closed.