Skip to main content

06. Hands-On Vulnerability Lab

In this hands-on lab, you will audit a vulnerable Coupon Redemption API, run an audit script to detect a Race Condition flaw, and implement an atomic threading lock remediation.


๐Ÿงช Lab Scenarioโ€‹

Step 1: Vulnerable Coupon API (vulnerable_coupon.py)โ€‹

# vulnerable_coupon.py
import time
from flask import Flask, request, jsonify

app = Flask(__name__)

COUPONS = {"DISCOUNT50": {"discount": 50, "used": False}}
USER_BALANCE = 0

@app.route('/api/v1/redeem', methods=['POST'])
def redeem():
global USER_BALANCE
data = request.get_json()
code = data.get("code")

coupon = COUPONS.get(code)
if not coupon or coupon["used"]:
return jsonify({"error": "Invalid or already used coupon"}), 400

# VULNERABLE: Artificial delay simulates DB query without mutex lock!
time.sleep(0.1)

USER_BALANCE += coupon["discount"]
coupon["used"] = True

return jsonify({"message": "Coupon redeemed", "new_balance": USER_BALANCE})

if __name__ == '__main__':
app.run(port=5008)

Step 2: Race Condition Audit Script (audit_race.py)โ€‹

# audit_race.py
import threading
import requests

URL = "http://localhost:5008/api/v1/redeem"

def send_request():
resp = requests.post(URL, json={"code": "DISCOUNT50"})
print(f"Status: {resp.status_code} | Body: {resp.text}")

print("=== SENDING CONCURRENT REDEMPTION REQUESTS ===")
t1 = threading.Thread(target=send_request)
t2 = threading.Thread(target=send_request)

t1.start()
t2.start()

t1.join()
t2.join()

Step 3: Secure Mutex Lock Fix (secure_coupon.py)โ€‹

# secure_coupon.py
import threading
from flask import Flask, request, jsonify

app = Flask(__name__)
lock = threading.Lock() # SECURE: Mutex Lock

COUPONS = {"DISCOUNT50": {"discount": 50, "used": False}}
USER_BALANCE = 0

@app.route('/api/v1/redeem', methods=['POST'])
def redeem_secure():
global USER_BALANCE
data = request.get_json()
code = data.get("code")

# SECURE FIX: Atomic execution block via Mutex Lock
with lock:
coupon = COUPONS.get(code)
if not coupon or coupon["used"]:
return jsonify({"error": "Invalid or already used coupon"}), 400

USER_BALANCE += coupon["discount"]
coupon["used"] = True

return jsonify({"message": "Coupon redeemed successfully", "new_balance": USER_BALANCE})

if __name__ == '__main__':
app.run(port=5008)

Next Chapter: 07. References & Taxonomies โ†’