Learning API Security Through Hands-On Exploration with crAPI

Learning API Security Through Hands-On Exploration with crAPI


As someone diving deeper into ethical hacking and security testing, I wanted a way to get practical experience working with insecure APIs in a controlled environment. That’s why I decided to take on a personal project using crAPI (Completely Ridiculous API) — a vulnerable API-based application designed specifically for learning and testing API security flaws.

Instead of just reading about vulnerabilities or watching tutorials, I wanted to interact directly with real API endpoints, manipulate requests, test authentication logic, and try to find ways systems could be abused if implemented incorrectly. Throughout this project, I documented every step I took, including the API calls I made, the tools I used, and the vulnerabilities I discovered.

The goal wasn’t just to follow a path — it was to explore, test, and better understand the world of API security through active experimentation. In the process, I used tools like Postman, Burp Suite, FFUF, and MailHog, and learned how to think more like an attacker when looking at API design.

Objectives

At the start, I laid out some clear goals for what I wanted to achieve with this project:

  • Understand how modern APIs are built and how they can be attacked
  • Practice identifying common API vulnerabilities like broken authentication or excessive data exposure
  • Gain hands-on experience with security testing tools used in real-world engagements
  • Document my process and findings for future reference and learning
  • Build confidence in analyzing, testing, and exploiting API-based applications

By the end of the project, I wanted to have a clearer picture of what makes an API secure — and more importantly, what makes one vulnerable.


What is crAPI?

crAPI (short for Completely Ridiculous API) is an intentionally vulnerable API-based web application built for security testing and education. Unlike traditional web applications that might have static pages or limited interaction, crAPI is built entirely around API calls. It includes features like user authentication, vehicle profiles, shopping carts, media uploads, and community forums — all powered by backend APIs.

Article content
crAPI

It’s designed to reflect how many real-world apps function today: the frontend (web or mobile) talks to the backend using RESTful JSON APIs. This makes it a great learning tool for understanding how attackers target APIs and what happens when the underlying security isn’t properly implemented.

What Are APIs and Why Do They Matter?

APIs — or Application Programming Interfaces — are how different software systems talk to each other. In modern apps, especially those with separate frontends and backends, APIs are what handle user data, manage sessions, update content, and process business logic.

For example, when you open a mobile app and view your profile, it’s likely using a GET /user/profile API call behind the scenes. When you update your settings, it might use a PUT /user/settings call. APIs are the backbone of modern application logic.

Because they sit between users and sensitive backend services, APIs have become a major target for attackers. If not properly secured, APIs can expose private data, allow unauthorized access, or enable manipulation of system behavior. That’s why understanding API security — and the common mistakes developers make — is so important.


OWASP API Security Top 10: What I Kept in Mind

As I worked through this project, I constantly found myself referencing the OWASP API Security Top 10. These are the most common and dangerous security issues found in APIs, and they acted like a checklist of what to watch out for.

Here’s a quick breakdown of each one and what it means in simple terms:

1. Broken Object Level Authorization (BOLA): This happens when the app doesn’t check if you’re allowed to see or change something — like reading someone else’s messages just by changing a number in the URL.

2. Broken Authentication: If login or password systems aren’t built securely, attackers can log in as someone else without permission.

3. Broken Object Property Level Authorization: Sometimes you shouldn’t see everything about an object — like someone’s private info on their profile — but the API gives it to you anyway.

4. Unrestricted Resource Consumption: If the API doesn’t limit how much you can ask from it, someone can overload it and slow it down or crash it — kind of like spam calling a phone line.

5. Broken Function Level Authorization: Even if you’re not an admin, the API may still let you do admin things — like deleting other users — if it doesn’t double-check your role.

6. Unrestricted Access to Sensitive Business Flows: Important business actions (like canceling orders or transferring money) might be open to anyone using the API — even if they’re not supposed to have access.

7. Server-Side Request Forgery (SSRF): If the API fetches web pages or files and doesn’t verify what you give it, you could trick it into accessing internal company systems.

8. Security Misconfiguration: APIs sometimes come with settings left open or unprotected — like leaving a door unlocked. Attackers look for these easy wins.

9. Improper Inventory Management: Old or hidden APIs may still be running without anyone noticing — and if they aren’t patched or protected, attackers can find and abuse them.

10. Unsafe Consumption of APIs: If your app uses third-party APIs and blindly trusts whatever they send back, attackers can use that to sneak in harmful data or commands.


Environment Setup and Preparation

Before diving into the challenges, I first set up the necessary environment to interact with crAPI and perform API security testing.

crAPI Deployment

I deployed crAPI (Completely Ridiculous API) locally using Docker and Docker Compose. After pulling the required containers and starting the services, I verified that the application was running correctly by accessing the crAPI web interface at http://localhost:8888.

Article content
crAPI Running

User Creation

To simulate realistic user behavior and test access controls, I created two separate accounts:

  • Edward (ed@example.com)
  • Sam (sam@example.com)

Article content
Signup

These users served as the foundation for authorization and privilege testing throughout the challenges.

Authentication and JWT Setup

After logging in as both Edward and Sam via the /identity/api/auth/login endpoint, I captured each user’s JWT from the API response.

To streamline testing, I saved these tokens as global variables in Postman:

  • jwt_ed: JWT for Edward
  • jwt_sam: JWT for Sam

Article content
Login Success

This allowed me to easily switch between user sessions by referencing these variables in the Authorization header:

Authorization: Bearer {{jwt_ed}}   // or {{jwt_sam}}        

With the environment, users, and authentication in place, I was ready to begin testing the crAPI endpoints and uncovering vulnerabilities.


Challenge 1: Accessing Details of Another User’s Vehicle (BOLA)

This challenge demonstrated a Broken Object Level Authorization (BOLA) vulnerability, where the API failed to properly restrict access to objects belonging to other users.

To start, I authenticated as Edward and explored the API using Postman. While looking through the community-related endpoints, I sent a request to:

GET /community/api/v2/community/posts/recent        

The response contained several public user posts. What stood out was that each post also included sensitive user information such as their nickname, email address, and most importantly, a vehicleid in UUID format. These UUIDs were not tied to my user and shouldn’t have been visible.

Article content
/recent Results

I copied one of the exposed vehicle UUIDs and used it in another request while still authenticated as Edward:

GET /identity/api/v2/vehicle/{uuid}/location        
Article content
GPS Success
Article content
GPS Success #2

After replacing the path variable with the leaked vehicleid, the endpoint returned that user’s vehicle location data (GPS coordinates). This confirmed the vulnerability: there was no authorization check to confirm whether Edward should have access to that vehicle’s location. Any authenticated user could simply plug in another user’s UUID and retrieve private information.


Challenge 2: Access Mechanic Reports of Other Users (BOLA)

This next BOLA vulnerability involved mechanic reports submitted by users through the crAPI interface.

Article content
Ed’s Registered Car 
Article content
Ed’s Car

Before I could submit a report, I ensured Edward had a vehicle registered to his account. I added one through the web interface using a VIN and a pincode that was sent via email, accessed using the MailHog interface on port 8025. Once the vehicle was added, I verified it with:

GET /identity/api/v2/vehicle/vehicles        
Article content
/vehicles Ed

The response confirmed that a vehicle was linked to Edward’s account. With this in place, I submitted a mechanic request using the following endpoint:

POST /workshop/api/merchant/contact_mechanic        
Article content
POST /contact Mechanic

In the body, I included the mechanic code, a test problem description, Edward’s VIN, and a mechanic API callback URL pointing to the receive_report endpoint. The response included a direct report link and a numeric report ID. This report belonged to Edward.

To explore the vulnerability, I made a new request to view that report:

GET /workshop/api/mechanic/mechanic_report?report_id=6        
Article content
Ed’s Report

To escalate the test, I modified the report_id parameter manually and sent additional requests with nearby values like 5 and 3. I used Burp Suite’s Intruder tool to automate this and observe the responses.

Article content
ReportID = 5
Article content
ReportID = 3

Several of the modified IDs returned valid mechanic reports submitted by other users. These reports contained sensitive service request information and user identifiers. No authentication or ownership check was done on the mechanic report endpoint. Even though I was logged in as Edward, I was able to retrieve other users’ reports simply by changing the ID value.

This was another example of Broken Object Level Authorization — the API did not verify ownership or apply access restrictions on a per-object basis.


Challenge 3: Reset the Password of a Different User (Improper Inventory Management & Broken Authentication)

This challenge focused on gaining unauthorized control of another user’s account by manipulating the password reset process. My target for this test was the user adam007@example.com, whose email I had already discovered earlier through a community post response.

I began by initiating a password reset request using the following endpoint:

POST /identity/api/auth/forget-password        
Article content
/forget-password for Adam

In the request body, I used Adam’s email. The API responded with a success message indicating that an OTP (one-time password) had been sent to the specified address. Since I had access to MailHog at http://localhost:8025, I opened it and retrieved the OTP sent to Adam’s email.

Initially, I tried submitting the OTP using this endpoint:

POST /identity/api/auth/v3/check-otp        

However, this version of the endpoint was rate-limited and quickly locked me out after a few incorrect attempts. Recognizing that the API used versioning, I tested the previous version:

POST /identity/api/auth/v2/check-otp        

This version of the endpoint lacked brute-force protections entirely. It accepted unlimited attempts without locking me out. I fuzzed the OTP using a wordlist of 0000–9999 and quickly found the correct 4-digit code.

Article content
Ffuf used
Article content
Correct OTP Double-check
Article content
/v3 OTP Check Success

With that OTP, I was able to submit a password reset request with a new password of my choice. After confirmation, I attempted to log in as Adam using:

POST /identity/api/auth/login        

I entered Adam’s email and the new password I set, and successfully received a new JWT. This meant I had fully taken over his account.

Article content
Successful Password Change

The vulnerability here was two-fold. First, there was a Broken Authentication issue — the OTP reset flow didn’t require validation against the current user session or ensure the user owned the email. Second, it demonstrated Improper Inventory Management — the older version of the API (v2) was still accessible and lacked security checks that the newer version (v3) had implemented. The existence of a legacy but insecure version of a critical endpoint created an exploitable gap.


Challenge 4: Find an API Endpoint That Leaks Sensitive Info of Other Users (Excessive Data Exposure)

This challenge was about identifying endpoints that returned more information than necessary, particularly sensitive data like emails.

Since I already had working tokens for both ed@example.com and sam@gmail.com, I used those to explore authenticated GET requests. While browsing the API in Postman, I came across this endpoint:

GET /community/api/v2/community/posts/recent        

This endpoint returned recent community posts, but more importantly, it included detailed user info for each post author — including email addresses and vehicle UUIDs, which are both sensitive identifiers.

Here’s the actual response I received:

{
    "posts": [
        {
            "id": "5we2dJ2siog8cZvR7fzyrQ",
            "title": "Title 3",
            "content": "Hello world 3",
            "author": {
                "nickname": "Robot",
                "email": "robot001@example.com",
                "vehicleid": "4bae9968-ec7f-4de3-a3a0-ba1b2ab5e5e5",
                "profile_pic_url": "",
                "created_at": "2025-04-22T13:56:38.296Z"
            },
            "comments": [],
            "authorid": 3,
            "CreatedAt": "2025-04-22T13:56:38.296Z"
        },
        {
            "id": "xCqTFAKyfM7jcFwCwqdMrC",
            "title": "Title 2",
            "content": "Hello world 2",
            "author": {
                "nickname": "Pogba",
                "email": "pogba006@example.com",
                "vehicleid": "cd515c12-0fc1-48ae-8b61-9230b70a845b",
                "profile_pic_url": "",
                "created_at": "2025-04-22T13:56:38.296Z"
            },
            "comments": [],
            "authorid": 2,
            "CreatedAt": "2025-04-22T13:56:38.296Z"
        },
        {
            "id": "9WZZmpeYYJyFQDNWMHnvUo",
            "title": "Title 1",
            "content": "Hello world 1",
            "author": {
                "nickname": "Adam",
                "email": "adam007@example.com",
                "vehicleid": "f89b5f21-7829-45cb-a650-299a61090378",
                "profile_pic_url": "",
                "created_at": "2025-04-22T13:56:38.292Z"
            },
            "comments": [],
            "authorid": 1,
            "CreatedAt": "2025-04-22T13:56:38.292Z"
        }
    ],
    "next_offset": null,
    "previous_offset": null,
    "total": 3
}        

Right away, it was clear that this endpoint exposed:

  • Full email addresses for every post author
  • Vehicle UUIDs, which were later useful in the BOLA challenges
  • Timestamps for account creation
  • Empty but present profile_pic_url fields

None of this information is necessary just to view a list of community posts. In a real-world API, you’d typically only want to return a display name or username — not contact info or internal identifiers.

This is a textbook example of Excessive Data Exposure. The API trusted the frontend too much and pushed data that could be used for user enumeration, spam, or further privilege escalation attacks.


Challenge 5: Leak Internal Property of a Video (Excessive Data Exposure)

After uploading a profile video through the crAPI web interface under Edward’s account, I returned to the API and inspected the user’s data using this endpoint:

GET /identity/api/v2/user/dashboard        
Article content
Dashboard #1
Article content
Dashboard #2

This revealed a video_id, which I used in the following PUT request:

PUT /identity/api/v2/user/videos/{video_id}        

In the response body, I discovered a field called:

"conversion_params": "-v codec h264"        

This parameter wasn’t meant to be user-visible — it’s an internal configuration related to how the server processes uploaded video content. Knowing this would later help with another challenge, but on its own, it was already an Excessive Data Exposure issue.

Internal properties like conversion_params should never be exposed to users unless there's a legitimate need, and even then, only with proper access controls and filtering. Instead, I was able to freely access and view it just by being a regular authenticated user.


Challenge 6: Triggering a Layer 7 DoS via Unrestricted Resource Consumption

This challenge was all about identifying and exploiting a vulnerability where the API doesn’t properly limit how many times a request can be repeated — a setup for a denial-of-service attack at the application layer.

After previously using the POST /workshop/api/merchant/contact_mechanic endpoint during earlier testing, I already knew it accepted a few interesting parameters, including:

{
  "mechanic_code": "TRAC_JHN",
  "problem_details": "My car is haunted.",
  "vin": "8CDEX84ZSDE097388",
  "mechanic_api": "http://localhost:8888/workshop/api/mechanic/receive_report",
  "repeat_request_if_failed": false,
  "number_of_repeats": 1
}        

For this challenge, I modified the last two fields to look like this:

"repeat_request_if_failed": true,
"number_of_repeats": 500        

I sent the updated payload using Postman with one of my authenticated users (in this case, Edward), and got this response:

{
    "message": "Service Unavailable. Seems like ou caused a layer 7 DoS :)"
}        
Article content
DoS Success

This error response confirmed the system couldn’t handle the volume of repeated requests — a classic Unrestricted Resource Consumption vulnerability. The server tried to fulfill the repeated calls but hit a processing limit, crashing under the load.

In a production environment, this kind of behavior could be abused to cause major performance issues or even full outages by overwhelming the backend with resource-heavy operations — all without needing elevated permissions.

This was a clear example of why rate limiting and resource controls are essential parts of API security, especially for endpoints that trigger workflows or external API calls.


Challenge 7: Deleting Another User’s Video (Broken Function Level Authorization)

This challenge explored how poorly implemented function-level access control can allow users to perform administrative-level actions they shouldn’t have access to — a clear Broken Function Level Authorization vulnerability.

To begin, I used Sam’s account to upload a profile video through the web interface (via the profile section). Once the video was uploaded, I switched over to Postman and sent a request to the GET /identity/api/v2/user/dashboard endpoint while authenticated as Sam to retrieve the details, including the video_id. The response looked like this:

{
  "id": 2,
  "name": "Sam",
  "email": "sam@example.com",
  "video_id": 7,
  ...
}        
Article content
Sam’s Dashboard

With Sam’s video ID in hand, I switched back to Edward’s account (using the jwt_ed token) and tested the following endpoint:

PUT /identity/api/v2/user/videos/7        

The request was accepted but didn’t delete the video. It returned a message saying the video couldn’t be found for Edward, which made sense — the system still tried to match the video ID to the authenticated user.

At this point, I changed two things:

  1. The HTTP method from PUT to DELETE
  2. The URL path from /user/ to /admin/

Final request:

DELETE /identity/api/v2/admin/videos/7        
Article content
Deleted Video Success

With Edward’s JWT still in use, I sent the request, and it successfully deleted Sam’s video. I confirmed it by sending another request to the GET /identity/api/v2/user/dashboard endpoint while authenticated as Sam — the video_url and video_name fields were now gone.

This confirmed that non-admin users could delete other users’ content by modifying the endpoint path and HTTP method — a serious flaw in how function-level permissions are enforced.


Challenge 8: Getting an Item for Free (Mass Assignment)

In this challenge, I focused solely on Edward’s user account to explore a Mass Assignment vulnerability.

After logging into crAPI as Edward, I used the Shop section to place an order for a product. Once the order was placed, I grabbed Edward’s order ID by sending:

GET /workshop/api/shop/orders/all        

This returned the order list specific to Edward. From that response, I identified the order ID — in my case, it was something like:

{
  "order_id": 6,
  ...
}        
Article content
All Orders

Then, I tested whether I could manipulate this order post-purchase. I sent a PUT request to:

PUT /workshop/api/shop/orders/6        
Article content
Ed’s Order Before

With a modified request body:

{
  "product_id": 2,
  "quantity": 5
}        
Article content
Ed’s Updated Order

Surprisingly, the server accepted the update — despite this order already being finalized via the UI. This confirmed that the API didn’t restrict what properties a user could change after purchase.

To finish the flow, I submitted a return request:

GET /workshop/api/shop/orders/return_order?order_id=6        
Article content
Successful Return 

The response returned a QR code indicating a return for five items instead of one, which could be used to get a refund for more than I had originally purchased. This was a clear example of a mass assignment vulnerability, where the API allowed unrestricted manipulation of object properties without validation.


Challenge 9: Increasing Account Balance via Negative Value Product (Mass Assignment)

This challenge built directly on the previous one, continuing with Edward’s account.

I started by reviewing the products available in the store via:

GET /workshop/api/shop/products        
Article content
/products

This showed me the current list of store products. Then I tested whether the API would accept new product creation by submitting a POST request to the same endpoint with the following body:

{
  "name": "Refund Exploit",
  "price": "-1000.0"
}        
Article content
POST New Product

Surprisingly, the API allowed this, and the product appeared in the product list with a negative price. This suggested that the backend lacked proper validation on submitted product values.

Next, I placed an order for the newly created item using Edward’s credentials:

Article content
Before
Article content
Exploit #1
Article content
Exploit #2

The order processed successfully, and Edward’s account balance increased by $2000 as a result.

This challenge again showcased a mass assignment vulnerability — the API trusted user input when it shouldn’t have, and lacked validation checks for values like price. It also exposed a business logic flaw, where the API failed to restrict actions that could result in profit rather than loss.


Challenge 10: Update Internal Video Properties (Mass Assignment)

In this challenge, the goal was to find and modify an internal property of a video that should not be user-editable, specifically targeting the conversion_params value.

First, I made sure Edward had a profile video uploaded by using the dashboard endpoint:

GET /identity/api/v2/user/dashboard        

This returned key information including the video_id, video_name, and a field called conversion_params, which was set to:

-v codec h264        

To test whether this parameter could be modified, I used the following endpoint:

PUT /identity/api/v2/user/videos/{{video_id}}        

I crafted a request body that attempted to modify the conversion_params field:

{
  "conversion_params": "-v codec h265"
}        
Article content
Successful Mass Assignment

After sending the request with Edward’s JWT (jwt_ed), I got a successful 200 OK response. This confirmed that the conversion_params value was changed from h264 to h265.

This shouldn’t have been allowed — the system exposed a low-level video processing parameter to the user, and allowed it to be edited without restriction. This confirmed a Mass Assignment vulnerability, where users can update object properties that should only be managed internally.

I did not go further to test command injection or chain it with SSRF. My focus was limited to confirming that conversion_params could be modified and that the application didn’t perform any validation or restriction on that internal field.


Conclusion

This project gave me a practical, in-depth look into API security testing by working directly with OWASP’s intentionally vulnerable API platform, crAPI. What began with a simple setup quickly evolved into a hands-on learning experience uncovering real, high-risk vulnerabilities that mirror the kinds of flaws found in modern production APIs.

Throughout this project, I was able to:

  • Explore the application’s functionality and enumerate key API endpoints
  • Access other users’ vehicle data through BOLA vulnerabilities
  • Extract sensitive mechanic reports by bypassing object-level restrictions
  • Perform an email reset on another user and take control of their account
  • Find endpoints that exposed internal user and mechanic data
  • Modify internal video parameters and identify mass assignment flaws
  • Abuse the “contact mechanic” feature to trigger a resource exhaustion denial of service
  • Exploit admin-only endpoints to delete another user’s video
  • Modify a return order for a refund on items never returned

Each of these steps helped me connect theoretical API security concepts with their real-world impact. It also taught me how to test authorization flows, manipulate request payloads, work with JWTs, and identify improper access control mechanisms using tools like Postman and Burp Suite.

Why This Matters

APIs are the backbone of most modern applications. They connect services, power user-facing features, and are often exposed directly to the internet. As a result, they’ve become a primary target for attackers. If APIs aren’t thoroughly tested and secured, the smallest oversight can result in major breaches — from unauthorized data exposure to complete system compromise.

By working through crAPI myself and focusing on exploitation techniques used in real-world testing scenarios, I’ve gained a stronger foundation in how attackers think and operate. More importantly, I now know what to look for — and how to report or remediate it — when dealing with live APIs in real environments.


#APIsecurity #OWASPTop10 #crAPI #BugBounty #PenetrationTesting #Cybersecurity #WebAppSecurity #JWT #MassAssignment #BOLA #BurpSuite #Postman #Docker #EthicalHacking #RedTeam #CTF #InfoSec #APIhacking #SecurityTesting #DevSecOps

Bibimariyam Dange

Internet marketing analyst at AI CERTS | Digital marketing | PGDM |

3w

It's inspiring to see your journey through API security, Jose. I thought you might be interested in AI Ethical hacking related events. Here's one for you! Join AI CERTs for a free webinar on "The Future of Ethical Hacking: AI as an Ally in Cyber Defense" on April 30, 2025. You can register at: https://bit.ly/m-ai-ethicalhacking. Participants will receive a certification, so consider sharing this with anyone interested!

Like
Reply

To view or add a comment, sign in

More articles by Jose Pacheco

Insights from the community

Others also viewed

Explore topics