Workflow Abuse

State Machine BypassProcess ManipulationWorkflow Bypass

Workflow Abuse at a glance

What it is: Vulnerabilities in multi-step business workflows that allow attackers to skip required steps, access intermediate states, or manipulate the workflow sequence.
Why it happens: Workflow abuse occurs when applications trust client-controlled state or fail to validate transitions, prerequisites, or step completion, allowing users to skip or manipulate process steps.
How to fix: Enforce validated state machines with server-side workflow state, verify prerequisites before transitions, and log all state changes for auditability and integrity.

Overview

Workflow abuse exploits flaws in multi-step business processes like checkout flows, approval workflows, onboarding processes, or order fulfillment. Attackers manipulate the sequence of steps to bypass required actions, access unauthorized states, or repeat beneficial steps.

Common vulnerabilities include missing server-side state validation, trusting client-side workflow state, allowing arbitrary state transitions, not validating prerequisites for each step, and failing to verify the complete workflow was followed. These attacks work by directly accessing later workflow steps, manipulating state parameters, or repeating steps out of order.

sequenceDiagram participant Attacker participant App participant DB Attacker->>App: GET /checkout?step=1 (cart) Attacker->>App: POST /checkout?step=4 (skip to confirmation)<br/>items=[{id:123, price:0}] App->>DB: INSERT order (no payment step) DB-->>App: Order created App-->>Attacker: 200 OK (order confirmed) Note over App: Missing: Step sequence validation<br/>Missing: Payment verification
A potential flow for a Workflow Abuse exploit

Where it occurs

Workflow abuse occurs in multi-step processes that rely on client-managed state or lack proper server-side validation of transitions, prerequisites, or step completion.

Impact

Workflow abuse leads to payment bypass where goods are obtained without payment, approval process circumvention, unauthorized account creation or privilege grants, inventory manipulation, fraud through repeated beneficial steps, and data integrity issues from incomplete workflows.

Prevention

Prevent logic flaws by enforcing server-side state machines with validated transitions, trusted state storage, unpredictable step IDs, atomic transactions, audit logging, timeouts, and verification of all required steps before completion.

Examples

Switch tabs to view language/framework variants.

E-commerce checkout allows skipping payment step

Direct URL access bypasses required workflow steps.

Vulnerable
Python • Flask — Bad
from flask import Flask, request, session

app = Flask(__name__)

@app.route('/checkout/step/<int:step>')
def checkout_step(step):
    # BUG: No validation of workflow progression
    if step == 1:
        return show_cart()
    elif step == 2:
        return show_payment()
    elif step == 3:
        # No check that payment was completed!
        create_order(session.get('cart'))
        return show_confirmation()
  • Line 13: No payment verification

Direct URL access bypasses required steps, allowing payment bypass.

Secure
Python • Flask — Good
from flask import Flask, request, session
from enum import Enum

class CheckoutState(Enum):
    CART = 1
    PAYMENT = 2
    CONFIRMATION = 3

ALLOWED_TRANSITIONS = {
    CheckoutState.CART: [CheckoutState.PAYMENT],
    CheckoutState.PAYMENT: [CheckoutState.CONFIRMATION]
}

@app.route('/checkout/step/<int:step>')
def checkout_step(step):
    current = session.get('checkout_state', CheckoutState.CART)
    requested = CheckoutState(step)
    
    # Validate transition
    if requested not in ALLOWED_TRANSITIONS.get(current, []):
        return 'Invalid workflow transition', 403
    
    if requested == CheckoutState.CONFIRMATION:
        if not session.get('payment_completed'):
            return 'Payment required', 403
        create_order(session['cart'])
    
    session['checkout_state'] = requested
    return render_step(requested)
  • Line 19: Transition validation
  • Line 23: Payment prerequisite check

Implement state machine with allowed transitions and prerequisite validation.

Engineer Checklist

  • Implement state machine with defined states and transitions

  • Validate prerequisites for each state transition

  • Store workflow state server-side, not in client

  • Use non-sequential, unpredictable step identifiers

  • Verify all required steps completed before finalization

  • Validate business rules at each transition

  • Log all state transitions with user context

  • Implement workflow timeouts

  • Use database transactions for atomic operations

  • Test by directly accessing intermediate URLs

  • Prevent duplicate submissions with idempotency

  • Add CSRF tokens to workflow forms

End-to-End Example

An e-commerce checkout workflow allows users to skip the payment step by directly accessing the order confirmation page.

Vulnerable
PYTHON
# Vulnerable: No state validation
@app.route('/checkout/<step>')
def checkout(step):
    if step == '1':
        return render_cart()
    elif step == '2':
        return render_payment()
    elif step == '3':
        # No validation that payment was completed!
        create_order(request.args.get('items'))
        return render_confirmation()
Secure
PYTHON
# Secure: Server-side state machine
from enum import Enum

class CheckoutState(Enum):
    CART = 1
    PAYMENT = 2
    CONFIRMATION = 3

ALLOWED_TRANSITIONS = {
    CheckoutState.CART: [CheckoutState.PAYMENT],
    CheckoutState.PAYMENT: [CheckoutState.CONFIRMATION],
}

@app.route('/checkout/<step>', methods=['GET', 'POST'])
@login_required
def checkout(step):
    # Get current workflow state from session
    current_state = session.get('checkout_state', CheckoutState.CART)
    requested_state = CheckoutState[step.upper()]
    
    # Validate transition is allowed
    if requested_state not in ALLOWED_TRANSITIONS.get(current_state, []):
        return "Invalid workflow transition", 403
    
    if requested_state == CheckoutState.PAYMENT:
        # Validate cart not empty
        if not session.get('cart_items'):
            return redirect('/checkout/CART')
        session['checkout_state'] = CheckoutState.PAYMENT
        return render_payment()
    
    elif requested_state == CheckoutState.CONFIRMATION:
        # Validate payment was completed
        if not session.get('payment_completed'):
            return redirect('/checkout/PAYMENT')
        
        # Create order atomically
        with db.transaction():
            order = create_order(
                user_id=current_user.id,
                items=session['cart_items'],
                payment_id=session['payment_id']
            )
            session.pop('cart_items')
            session.pop('payment_id')
            session['checkout_state'] = CheckoutState.CART
        
        return render_confirmation(order)

Discovery

Map all workflow URLs and try accessing later steps directly. Manipulate step parameters or state identifiers.

  1. 1. Map workflow endpoints

    http

    Action

    Enumerate all workflow step URLs through normal flow

    Request

    GET https://app.example.com/checkout?step=1,2,3,4

    Response

    Status: 200
    Body:
    {
      "note": "Sequential step URLs discovered, identifying progression pattern"
    }

    Artifacts

    workflow_map step_urls state_parameters
  2. 2. Test direct step access

    http

    Action

    Attempt to access later workflow steps without completing earlier ones

    Request

    GET https://app.example.com/checkout?step=4

    Response

    Status: 200
    Body:
    {
      "note": "Access granted to confirmation step without completing payment"
    }

    Artifacts

    step_bypass missing_validation
  3. 3. Test state parameter manipulation

    http

    Action

    Manipulate workflow state identifiers to skip steps

    Request

    POST https://app.example.com/checkout/submit
    Body:
    "{'workflow_state': 'completed', 'payment_done': true}"

    Response

    Status: 200
    Body:
    {
      "note": "Application accepts client-provided state without validation"
    }

    Artifacts

    state_manipulation client_state_trust

Exploit steps

Attacker identifies workflow steps and directly accesses later steps bypassing required actions like payment, approval, or verification.

  1. 1. Bypass payment step in checkout

    Skip to order confirmation

    http

    Action

    Directly access order confirmation without completing payment

    Request

    POST https://app.example.com/checkout/confirm
    Body:
    "{'items': [{'id': 123, 'quantity': 1}]}"

    Response

    Status: 200
    Body:
    {
      "note": "Order created and confirmed without payment processing"
    }

    Artifacts

    unpaid_order payment_bypass order_confirmation
  2. 2. Skip approval workflow

    Direct access to approved state

    http

    Action

    Access final approval step without manager review

    Request

    GET https://app.example.com/request/123/approve?bypass=true

    Response

    Status: 200
    Body:
    {
      "note": "Request marked as approved without authorization"
    }

    Artifacts

    approval_bypass unauthorized_approval
  3. 3. Manipulate multi-step registration

    Skip verification steps

    http

    Action

    Complete registration without email/phone verification

    Request

    POST https://app.example.com/register/complete
    Body:
    "{'verified': true, 'step': 'final'}"

    Response

    Status: 200
    Body:
    {
      "note": "Account created with full privileges without verification"
    }

    Artifacts

    unverified_account verification_bypass

Specific Impact

Financial loss from payment bypass, unauthorized account privileges, inventory fraud, and compromised business processes.

Fix

Implement a proper state machine with defined states and allowed transitions. Store workflow state server-side in sessions. Validate all prerequisites before allowing state transitions. Use database transactions for atomicity.

Detect This Vulnerability in Your Code

Sourcery automatically identifies workflow abuse vulnerabilities and many other security issues in your codebase.

Scan Your Code for Free