In Part 1 of this series, we hacked the "Vulnerable Bank API" by exploiting the "Big Three" of API security: Broken Object Level Authorization (BOLA), Broken Authentication, and Broken Object Property Level Authorization (BOPLA). We managed to view other users' transactions, forge authentication tokens to become an administrator, and even escalate privileges by manipulating JSON payloads.
But we aren't done yet.
While Part 1 focused on logic flaws in user access, Part 2 shifts the focus to the infrastructure itself.
In this article, we will see how configuration errors, legacy code, and unsafe integrations with modern AI features can lead to a system compromise. We will trick the server into attacking itself (SSRF), bypass firewalls, leak database credentials, and "jailbreak" an AI chatbot.
When we talk about Denial of Service (DoS), we usually think of a botnet flooding a server with traffic until it crashes. However, API4: Unrestricted Resource Consumption is more subtle. It's about the cost of a request. If an API endpoint triggers an expensive operation, like sending an email, processing a large file, or generating a complex report, an attacker can exhaust the organization's budget or resources with a relatively small number of requests.
I started by looking at the Password Reset functionality (POST /api/v1/forgot-password). This endpoint takes a username and triggers a backend process to generate a PIN and (presumably) send an email or SMS.
"If I spam this endpoint, will the server stop me?"
3. The server responded with 200 OK for every single request.
There was no 429 Too Many Requests error. The response time didn't degrade. This means I could theoretically trigger millions of emails, potentially landing the bank's domain on a spam blacklist or costing them thousands in email provider fees (e.g., SendGrid/Twilio costs).
BFLA happens when an application relies on the UI to hide administrative buttons (like "Delete User") but fails to enforce those checks on the server. If I know the URL, can I use it as a regular user?
I logged in as Imelda (a standard user) and attempted to access the Delete User and Create Admin User endpoints, which are intended for Admins only.
Surprisingly, the application was Secure against this specific attack. The developers correctly implemented a backend check (likely a decorator, such as @requires_admin) that verifies the user's role before executing the function.
This vulnerability is tricky because it’s not technically a "bug." The code works exactly as written. The problem is that the code allows a user to abuse a legitimate business process in a way that hurts the company.
The bank allows users to create "Virtual Credit Cards" for secure online shopping (POST /api/virtual-cards/create). Creating a card likely incurs a fee from the card issuer (Visa/Mastercard) that the bank pays.
1. I captured a legitimate request to create a card.
2. Using Burp Intruder, I replayed this request 100 times with a "Null Payload" (sending the exact same request over and over).
3. The server created 100 distinct virtual cards for my account.
4. I have now cost the bank money and hoarded card numbers. If I do this thousands of times, I could exhaust the bank's allocated pool of card numbers.
Now we enter the critical zone. SSRF occurs when an API fetches data from a URL provided by the user. If the server doesn't validate that URL, we can trick the server into scanning its own internal network, accessing local files, or querying cloud metadata services (like AWS 169.254.169.254).
I found an endpoint: POST /upload_profile_picture_url. It takes a JSON body like {"image_url": "http://meli.traleor.com"}.
Step 1:
I sent https://traleor.com/medias/public/images/meli-imelda.original.jpg. The server fetched it and saved the image. This confirms the server has outbound internet access.
Step 2:
I tried to access the internal secret file I knew existed from the lab setup: http://192.168.1.238:5000/internal/secret.
Step 3:
I changed the IP to the Loopback Address (127.0.0.1), which refers to "localhost" or "this machine."
We now have the database credentials and the key used to sign JWTs.
This category covers everything from verbose error messages to default passwords. In this lab, I found two massive misconfigurations.
Cross-Origin Resource Sharing (CORS) tells a browser which websites are allowed to talk to your API.
I sent a request with the header: Origin: http://meli.traleor.com (simulating a malicious hacker's website).
The server responded with: Access-Control-Allow-Origin: http://meli.traleor.com.
This is a "Reflected Origin" vulnerability. It means if I trick a victim into visiting my website, my JavaScript can make authenticated requests to the bank API on their behalf, and the browser will allow it. This is instant Account Takeover.
Using the SSRF vulnerability from earlier, I decided to aim for the configuration file.
The Payload: {"image_url": "http://127.0.0.1:5000/internal/config.json"}
The server fetched and saved its own config file.
"Zombie APIs" are old versions of an API (v1, v2) that were supposed to be retired but are still running. They often lack the security patches applied to the new version (v3).
The current application (v3) uses a secure password reset flow that emails a masked PIN.
I simply changed the URL in Postman from /api/v3/forgot-password to /api/v1/forgot-password.
The v1 endpoint was still active. Even worse, it returned the 3-digit reset PIN directly in the JSON response. I didn't need access to the victim's email; the API just gave me the code to hijack their account.
This is the newest addition to the OWASP Top 10. It deals with the risks of integrating Third-Party APIs, such as LLMs (Large Language Models), like ChatGPT. If we trust the AI too much, it becomes a "Confused Deputy."
The bank has an AI support bot. I checked its system info (GET /api/ai/system-info) and saw "database_access": true.
By using natural language, I bypassed all BOLA and RBAC controls. I didn't need to know SQL; I just needed to ask nicely.
While testing the profile upload, I also tried to use the file:// protocol instead of http://.
Payload: {"image_url": "file:///etc/passwd"}
The server returned a 500 Error with the message: "No connection adapters were found for 'file:///etc/passwd'".
While this exploit didn't return the file content (because the Python requests library doesn't support local files by default), the verbose error message confirmed a vulnerability. The server tried to process it. If the developer switches libraries to urllib in the future, this becomes a critical file disclosure vulnerability.
Over the course of this two-part series, we have exploited all the OWASP API Top 10 in the "Vulnerable Bank API." We went from simple data leaks to full compromise.
Read it here: Hacking The Vulnerable Bank API Part 1
And with that, the 'Hacking a Vulnerable Bank API' series comes to an end!