wstg-busl-06
Test ID
WSTG-BUSL-06
Test Name
Testing for the Circumvention of Work Flows
High-Level Description
Workflow circumvention testing examines whether an application properly enforces the intended sequence of steps in multi-step processes. Many business processes require specific steps to be completed in order (e.g., shopping cart → checkout → payment → confirmation). Attackers may attempt to skip steps, revisit completed steps, or access endpoints out of sequence to bypass security controls, avoid payments, or gain unauthorized access.
What to Check
Workflow Elements
Common Workflow Vulnerabilities
| Vulnerability | Example |
|---|
| Step skipping | Skip payment, go directly to order confirmation |
| Step repetition | Repeat discount application |
| State manipulation | Change order after payment |
| Direct access | Access confirmation page without completing flow |
| Parallel execution | Start multiple flows, complete one |
How to Test
Step 1: Map the Workflow
Step 2: Test Direct Step Access
curl -s -X POST "https://target.com/api/checkout/confirm" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"order_id": "12345"}'
curl -s "https://target.com/api/orders/12345" \
-H "Authorization: Bearer $TOKEN"
curl -s -X POST "https://target.com/api/checkout/confirm" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"cart_id": "abc123",
"shipping_id": "ship123"
}'
Step 3: Test Step Skipping
#!/bin/bash
TOKEN="your_auth_token"
BASE="https://target.com"
echo "Step 1: Start checkout"
checkout=$(curl -s -X POST "$BASE/api/checkout/start" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"cart_id": "cart123"}')
checkout_id=$(echo $checkout | jq -r '.checkout_id')
echo "Skip step 2, go to step 3..."
result=$(curl -s -X POST "$BASE/api/checkout/payment" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"checkout_id\": \"$checkout_id\",
\"payment_method\": \"card\",
\"card_token\": \"tok_test\"
}")
echo "Result: $result"
Step 4: Test State Manipulation After Completion
curl -s -X PUT "https://target.com/api/checkout/abc123/shipping" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"address": "New Address",
"city": "Attacker City"
}'
curl -s -X POST "https://target.com/api/orders/order123/apply-coupon" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"code": "DISCOUNT50"}'
Step 5: Test Workflow Token/State Bypass
for id in 95 96 97 98 99 100 101 102; do
response=$(curl -s "https://target.com/api/checkout/checkout_$id/confirm" \
-H "Authorization: Bearer $TOKEN")
echo "checkout_$id: $response"
done
curl -s -X POST "https://target.com/api/checkout/confirm" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"checkout_id": "checkout_99",
"state_token": "modified_token",
"step": "complete"
}'
Step 6: Test Parallel Workflow Execution
#!/bin/bash
for i in {1..5}; do
curl -s -X POST "https://target.com/api/checkout/start" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"cart_id": "cart123"}' &
done
wait
Step 7: Test Registration/Onboarding Bypass
curl -s "https://target.com/api/dashboard" \
-H "Authorization: Bearer $NEW_USER_TOKEN"
curl -s -X POST "https://target.com/api/users/complete-profile" \
-H "Authorization: Bearer $UNVERIFIED_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Test User"}'
curl -s "https://target.com/api/sensitive-data" \
-H "Authorization: Bearer $NO_2FA_TOKEN"
Tools
Manual Testing
| Tool | Description | Usage |
|---|
| Burp Suite | Intercept workflow | Modify/replay requests |
| Postman | API workflow testing | Collection runners |
| Browser DevTools | Monitor state changes | Track tokens/cookies |
Automated
| Tool | Description |
|---|
| Burp Macros | Automate multi-step flows |
| Custom scripts | Workflow fuzzing |
Example Commands/Payloads
Workflow State Manipulation
{"current_step": 5}
{"step": "complete"}
{"workflow_state": "finished"}
{"payment_status": "completed"}
{"verified": true}
{"approved": true}
{"skip_verification": true}
{"express_checkout": true}
{"bypass_review": true}
Workflow Circumvention Tester
import requests
class WorkflowTester:
def __init__(self, base_url, token):
self.base_url = base_url
self.headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
self.findings = []
def test_direct_step_access(self, steps):
"""Test if later steps can be accessed directly"""
for i, step in enumerate(steps):
if i == 0:
continue
response = requests.request(
step["method"],
f"{self.base_url}{step['endpoint']}",
headers=self.headers,
json=step.get("payload", {})
)
if response.status_code == 200:
self.findings.append({
"type": "direct_access",
"step": i + 1,
"endpoint": step["endpoint"],
"result":
})
:
.findings.append({
: ,
: i + ,
: step[],
:
})
():
first = steps[]
r1 = requests.request(
first[],
,
headers=.headers,
json=first.get(, {})
)
r1.status_code != :
i (, (steps)):
step = steps[i]
response = requests.request(
step[],
,
headers=.headers,
json=step.get(, {})
)
response.status_code == :
.findings.append({
: ,
: i + ,
: step[],
:
})
():
i (completed_step):
step = steps[i]
step[] [, ]:
response = requests.request(
step[],
,
headers=.headers,
json=step.get(, {})
)
response.status_code == :
.findings.append({
: ,
: i + ,
: step[],
:
})
():
()
vulnerabilities = [f f .findings f[]]
()
()
vulnerabilities:
()
v vulnerabilities:
()
.findings
tester = WorkflowTester(, )
checkout_steps = [
{: , : , : {: }},
{: , : , : {: }},
{: , : , : {: }},
{: , : , : {}},
]
tester.test_direct_step_access(checkout_steps)
tester.test_step_skipping(checkout_steps)
tester.generate_report()
Remediation Guide
1. Implement Workflow State Machine
from enum import Enum
from datetime import datetime
class CheckoutState(Enum):
INITIATED = "initiated"
CART_REVIEWED = "cart_reviewed"
SHIPPING_ADDED = "shipping_added"
PAYMENT_ADDED = "payment_added"
CONFIRMED = "confirmed"
COMPLETED = "completed"
class CheckoutStateMachine:
VALID_TRANSITIONS = {
CheckoutState.INITIATED: [CheckoutState.CART_REVIEWED],
CheckoutState.CART_REVIEWED: [CheckoutState.SHIPPING_ADDED],
CheckoutState.SHIPPING_ADDED: [CheckoutState.PAYMENT_ADDED],
CheckoutState.PAYMENT_ADDED: [CheckoutState.CONFIRMED],
CheckoutState.CONFIRMED: [CheckoutState.COMPLETED],
CheckoutState.COMPLETED: []
}
def can_transition(self, current, target):
"""Check if transition is valid"""
allowed = self.VALID_TRANSITIONS.get(current, [])
return target in allowed
def transition(self, checkout, target_state):
"""Perform state transition with validation"""
if not self.can_transition(checkout.state, target_state):
raise WorkflowViolationError(
f"Cannot transition from {checkout.state} to {target_state}"
)
checkout.state = target_state
checkout.state_history.append({
"from": checkout.state,
"to": target_state,
"timestamp": datetime.utcnow()
})
checkout
():
checkout = get_checkout(request.json[])
checkout.state != CheckoutState.SHIPPING_ADDED:
jsonify({
: ,
: ,
: checkout.state.value
}),
process_payment(checkout, request.json)
state_machine.transition(checkout, CheckoutState.PAYMENT_ADDED)
jsonify(checkout.to_dict())
2. Cryptographic State Tokens
import jwt
from datetime import datetime, timedelta
SECRET_KEY = "your-secret-key"
def generate_workflow_token(checkout_id, current_step, user_id):
"""Generate signed token for workflow state"""
payload = {
"checkout_id": checkout_id,
"step": current_step,
"user_id": user_id,
"completed_at": datetime.utcnow().isoformat(),
"exp": datetime.utcnow() + timedelta(hours=1)
}
return jwt.encode(payload, SECRET_KEY, algorithm="HS256")
def validate_workflow_token(token, expected_step, checkout_id, user_id):
"""Validate workflow token"""
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
if payload["checkout_id"] != checkout_id:
return False, "Invalid checkout"
if payload["user_id"] != user_id:
return False, "Invalid user"
if payload["step"] != expected_step - 1:
return False, f"Invalid step sequence"
return True, None
except jwt.ExpiredSignatureError:
return ,
jwt.InvalidTokenError:
,
():
prev_token = request.headers.get()
prev_token:
jsonify({: }),
valid, error = validate_workflow_token(
prev_token,
expected_step=,
checkout_id=request.json[],
user_id=current_user.
)
valid:
jsonify({: error}),
process_payment(request.json)
new_token = generate_workflow_token(
request.json[],
current_step=,
user_id=current_user.
)
jsonify({
: ,
: new_token
})
3. Server-Side Step Tracking
class WorkflowTracker:
def __init__(self, redis_client):
self.redis = redis_client
def record_step_completion(self, workflow_id, user_id, step):
"""Record completed step"""
key = f"workflow:{workflow_id}:{user_id}"
self.redis.sadd(key, step)
self.redis.expire(key, 3600)
def verify_prerequisites(self, workflow_id, user_id, target_step, required_steps):
"""Verify all required steps are completed"""
key = f"workflow:{workflow_id}:{user_id}"
completed = self.redis.smembers(key)
missing = set(required_steps) - completed
if missing:
return False, list(missing)
return True, None
def lock_completed_steps(self, workflow_id, user_id, step):
"""Lock step to prevent modification"""
key = f"workflow_lock:{workflow_id}:{user_id}"
self.redis.sadd(key, step)
def is_step_locked(self, workflow_id, user_id, step):
key =
.redis.sismember(key, step)
Risk Assessment
CVSS Score
| Finding | CVSS | Severity |
|---|
| Payment step bypass | 9.8 | Critical |
| Verification step bypass | 8.8 | High |
| Discount application after payment | 7.5 | High |
| Onboarding bypass | 6.5 | Medium |
| Step modification after completion | 6.5 | Medium |
CWE Categories
| CWE ID | Title | Description |
|---|
| CWE-841 | Improper Enforcement of Behavioral Workflow | Workflow bypass |
| CWE-306 | Missing Authentication for Critical Function | Step skipping |
| CWE-840 | Business Logic Errors | Logic flaw exploitation |
References
Checklist
[ ] Workflow steps mapped and documented
[ ] Direct step access tested
[ ] Step skipping tested
[ ] State manipulation tested
[ ] Backward navigation tested
[ ] Parallel workflow tested
[ ] Token/state prediction tested
[ ] Registration/onboarding bypass tested
[ ] Payment bypass tested
[ ] State machine enforcement verified
[ ] Findings documented
[ ] Remediation recommendations provided