Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Test Number of Times a Function Can Be Used Limits
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-16 | ✗→✓ | ▲ Improved | 237% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 123% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 150% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 182% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 185% | 0% |
WSTG-BUSL-05
Test Number of Times a Function Can Be Used Limits
Function usage limit testing examines whether an application properly enforces restrictions on how many times a user can perform specific actions. These limits protect against abuse, fraud, and resource exhaustion. Attackers may attempt to bypass these controls to gain unfair advantages, such as unlimited free trials, multiple coupon redemptions, or exceeding transaction limits.
| Technique | Description | | -------------------- | -------------------------- | | Session manipulation | New session resets counter | | Account switching | Multiple accounts | | Parameter tampering | Modify limit parameters | | Time manipulation | Change timestamps | | Race conditions | Parallel requests |
bash# Document limits from application behavior/documentation # Examples: # - 3 password reset attempts per hour # - 5 free downloads per day # - 10 API calls per minute # - 1 coupon per account # - $1000 daily transfer limit # Test to discover undocumented limits for i in {1..50}; do response=$(curl -s -X POST "https://target.com/api/download/free" \ -H "Authorization: Bearer $TOKEN" \ -w "\n%{http_code}") echo "Attempt $i: $response" done
bash#!/bin/bash # Test if limits are actually enforced LIMIT=5 ENDPOINT="https://target.com/api/action" TOKEN="your_token" echo "Testing limit enforcement..." for i in $(seq 1 $((LIMIT + 5))); do response=$(curl -s -X POST "$ENDPOINT" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"action": "test"}' \ -w "\nSTATUS:%{http_code}") status=$(echo "$response" | grep "STATUS:" | cut -d: -f2) if [ "$i" -le "$LIMIT" ]; then if [ "$status" != "200" ]; then echo "Attempt $i: UNEXPECTED FAILURE (expected success)" else echo "Attempt $i: SUCCESS (as expected)" fi else if [ "$status" == "200" ]; then echo "Attempt $i: [VULNERABILITY] Success beyond limit!" else echo "Attempt $i: BLOCKED (as expected)" fi fi done
bash# Get new session and test if limit resets # First, exhaust limit with current session for i in {1..10}; do curl -s -X POST "https://target.com/api/action" \ -H "Cookie: session=$SESSION1" > /dev/null done # Get new session NEW_SESSION=$(curl -s -c - "https://target.com/login" \ -d "user=$USER&pass=$PASS" | grep session | awk '{print $7}') # Try with new session response=$(curl -s -X POST "https://target.com/api/action" \ -H "Cookie: session=$NEW_SESSION") echo "After new session: $response" # If success, limits are per-session not per-user
bash#!/bin/bash # Test if creating multiple accounts bypasses limits # Limit: 3 free downloads per account # Attack: Create multiple accounts for account in {1..5}; do # Create new account curl -s -X POST "https://target.com/api/register" \ -H "Content-Type: application/json" \ -d "{ \"username\": \"testuser$account\", \"email\": \"test$account@temp-mail.com\", \"password\": \"Password123!\" }" # Get token token=$(curl -s -X POST "https://target.com/api/login" \ -H "Content-Type: application/json" \ -d "{ \"email\": \"test$account@temp-mail.com\", \"password\": \"Password123!\" }" | jq -r '.token') # Use free downloads for download in {1..3}; do curl -s -X GET "https://target.com/api/download/free" \ -H "Authorization: Bearer $token" > /dev/null echo "Account $account, Download $download: Done" done done
bash# Test if limits reset at specific times # First, exhaust daily limit for i in {1..10}; do curl -s -X POST "https://target.com/api/action" \ -H "Authorization: Bearer $TOKEN" > /dev/null done # Check if sending future timestamp bypasses curl -s -X POST "https://target.com/api/action" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"timestamp": "2025-12-31T00:00:00Z"}' # Test with modified Date header curl -s -X POST "https://target.com/api/action" \ -H "Authorization: Bearer $TOKEN" \ -H "Date: Mon, 31 Dec 2025 00:00:00 GMT"
bash# Try modifying limit-related parameters # If limit info is in response/request curl -s -X POST "https://target.com/api/action" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "action": "download", "remaining_limit": 999, "is_premium": true }' # Hidden parameter injection curl -s -X POST "https://target.com/api/action" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "action": "download", "bypass_limit": true, "unlimited": true }'
bash# Find if there's a way to reset limits # Check for reset endpoint curl -s -X POST "https://target.com/api/reset-limits" \ -H "Authorization: Bearer $TOKEN" # Check profile update curl -s -X PUT "https://target.com/api/user/profile" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"usage_count": 0}' # Check if deleting and recreating something resets limit curl -s -X DELETE "https://target.com/api/subscription" \ -H "Authorization: Bearer $TOKEN" curl -s -X POST "https://target.com/api/subscription/trial" \ -H "Authorization: Bearer $TOKEN"
| Tool | Description | Usage | | ------------------ | ----------------------- | ---------------------- | | Burp Intruder | Automated limit testing | Iterate until blocked | | Custom scripts | Limit bypass testing | Python/Bash automation | | Postman | API testing | Collection runners |
| Tool | Description | | ---------------- | ------------------ | | Burp Logger | Track all requests | | Excel/Sheets | Analyze patterns |
json// Premium status bypass {"is_premium": true} {"account_type": "enterprise"} {"subscription": "unlimited"} // Limit manipulation {"remaining_downloads": 999} {"usage_count": 0} {"limit_reset": true} // Timestamp manipulation {"timestamp": "2099-01-01T00:00:00Z"} {"created_at": "2020-01-01T00:00:00Z"}
python#!/usr/bin/env python3 import requests import time import json class LimitTester: def __init__(self, base_url, token): self.base_url = base_url self.headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } self.results = [] def test_hard_limit(self, endpoint, expected_limit, payload=None): """Test if hard limit is enforced""" if payload is None: payload = {} successes = 0 for i in range(expected_limit + 10): response = requests.post( f"{self.base_url}{endpoint}", headers=self.headers, json=payload ) if response.status_code == 200: successes += 1 else: break result = { "endpoint": endpoint, "expected_limit": expected_limit, "actual_successes": successes, "enforced": successes <= expected_limit, "vulnerable": successes > expected_limit } self.results.append(result) return result def test_session_reset_bypass(self, endpoint, login_endpoint, credentials): """Test if new session resets limits""" # Exhaust limit with session 1 for _ in range(20): requests.post( f"{self.base_url}{endpoint}", headers=self.headers ) # Get new session login_response = requests.post( f"{self.base_url}{login_endpoint}", json=credentials ) new_token = login_response.json().get("token") # Try with new session new_headers = {**self.headers, "Authorization": f"Bearer {new_token}"} response = requests.post( f"{self.base_url}{endpoint}", headers=new_headers ) result = { "test": "session_reset_bypass", "vulnerable": response.status_code == 200, "details": "New session resets limits" if response.status_code == 200 else "Limits persist" } self.results.append(result) return result def test_parameter_bypass(self, endpoint, bypass_params): """Test parameter-based limit bypass""" # First exhaust normal limit for _ in range(20): requests.post( f"{self.base_url}{endpoint}", headers=self.headers, json={} ) # Try with bypass parameters vulnerabilities = [] for param in bypass_params: response = requests.post( f"{self.base_url}{endpoint}", headers=self.headers, json=param ) if response.status_code == 200: vulnerabilities.append({ "param": param, "status": response.status_code }) result = { "test": "parameter_bypass", "vulnerable": len(vulnerabilities) > 0, "bypasses": vulnerabilities } self.results.append(result) return result def generate_report(self): """Generate test report""" print("\n=== LIMIT TESTING REPORT ===\n") vulnerable_count = sum(1 for r in self.results if r.get("vulnerable")) print(f"Total tests: {len(self.results)}") print(f"Vulnerabilities found: {vulnerable_count}") print("") for result in self.results: status = "[VULN]" if result.get("vulnerable") else "[OK]" print(f"{status} {result.get('endpoint', result.get('test'))}") if result.get("vulnerable"): for key, value in result.items(): if key not in ["endpoint", "test", "vulnerable"]: print(f" {key}: {value}") # Usage tester = LimitTester("https://target.com", "auth_token") # Test various limits tester.test_hard_limit("/api/download/free", expected_limit=5) tester.test_hard_limit("/api/password-reset", expected_limit=3) tester.test_hard_limit("/api/transfer", expected_limit=10) # Test bypass techniques tester.test_parameter_bypass("/api/download", [ {"is_premium": True}, {"bypass_limit": True}, {"remaining": 999} ]) tester.generate_report()
pythonfrom datetime import datetime, timedelta from functools import wraps class UsageLimiter: def __init__(self, redis_client): self.redis = redis_client def check_limit(self, user_id, action, limit, period_seconds): """Check if user is within usage limit""" key = f"limit:{user_id}:{action}" current = self.redis.get(key) if current is None: self.redis.setex(key, period_seconds, 1) return True, limit - 1 current = int(current) if current >= limit: ttl = self.redis.ttl(key) return False, 0 # Limit reached self.redis.incr(key) return True, limit - current - 1 def rate_limit(action, limit, period_seconds): """Decorator for rate limiting""" def decorator(f): @wraps(f) def wrapped(*args, **kwargs): user_id = get_current_user_id() allowed, remaining = limiter.check_limit( user_id, action, limit, period_seconds ) if not allowed: return jsonify({ "error": "Rate limit exceeded", "retry_after": period_seconds }), 429 response = f(*args, **kwargs) # Add rate limit headers response.headers["X-RateLimit-Limit"] = str(limit) response.headers["X-RateLimit-Remaining"] = str(remaining) return response return wrapped return decorator # Usage @app.route('/api/download/free') @rate_limit(action="free_download", limit=5, period_seconds=86400) def free_download(): return download_file()
pythonfrom sqlalchemy import Column, Integer, DateTime, func from datetime import datetime, timedelta class UsageTracking(Base): __tablename__ = 'usage_tracking' id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey('users.id')) action = Column(String(50)) count = Column(Integer, default=0) period_start = Column(DateTime) def check_and_increment(user_id, action, limit, period_hours=24): """Atomically check and increment usage""" period_start = datetime.utcnow() - timedelta(hours=period_hours) # Use database-level locking with Session(engine) as session: tracking = session.query(UsageTracking).filter( UsageTracking.user_id == user_id, UsageTracking.action == action, UsageTracking.period_start >= period_start ).with_for_update().first() if tracking is None: # First use in this period tracking = UsageTracking( user_id=user_id, action=action, count=1, period_start=datetime.utcnow() ) session.add(tracking) session.commit() return True if tracking.count >= limit: return False tracking.count += 1 session.commit() return True
pythonimport hashlib def get_device_fingerprint(request): """Generate device fingerprint for abuse detection""" components = [ request.headers.get('User-Agent', ''), request.headers.get('Accept-Language', ''), request.remote_addr, # Add more fingerprinting components ] return hashlib.sha256(''.join(components).encode()).hexdigest() def check_abuse_patterns(user_id, fingerprint): """Check for abuse patterns""" # Check if same fingerprint used by multiple accounts accounts_with_fingerprint = get_accounts_by_fingerprint(fingerprint) if len(accounts_with_fingerprint) > 3: flag_for_review(user_id, "Multiple accounts from same device") return True # Check for rapid account creation recent_accounts = get_accounts_created_recently(fingerprint, hours=24) if len(recent_accounts) > 2: flag_for_review(user_id, "Rapid account creation") return True return False
pythonclass TieredLimiter: TIERS = { 'free': { 'downloads': 5, 'api_calls': 100, 'transfers': 3 }, 'basic': { 'downloads': 50, 'api_calls': 1000, 'transfers': 20 }, 'premium': { 'downloads': 500, 'api_calls': 10000, 'transfers': 100 } } def get_limit(self, user, action): """Get limit based on user tier - from database, not request""" # IMPORTANT: Get tier from database, not from request tier = self.get_user_tier_from_db(user.id) return self.TIERS.get(tier, self.TIERS['free']).get(action, 0) def get_user_tier_from_db(self, user_id): """Always fetch tier from database""" user = User.query.get(user_id) return user.subscription_tier if user else 'free'
| Finding | CVSS | Severity | | ---------------------------------- | ---- | -------- | | Financial transaction limit bypass | 9.8 | Critical | | Unlimited free trial abuse | 6.5 | Medium | | Download quota bypass | 5.3 | Medium | | API rate limit bypass | 5.3 | Medium | | Vote/rating manipulation | 4.3 | Medium |
| CWE ID | Title | Description | | ----------- | ------------------------------------------- | -------------------- | | CWE-770 | Allocation of Resources Without Limits | Missing usage limits | | CWE-799 | Improper Control of Interaction Frequency | Rate limit bypass | | CWE-841 | Improper Enforcement of Behavioral Workflow | Workflow bypass |
[ ] Function usage limits identified
[ ] Hard limit enforcement tested
[ ] Session-based reset bypass tested
[ ] Account-based bypass tested
[ ] Time manipulation tested
[ ] Parameter tampering tested
[ ] Race condition bypass tested
[ ] Limit reset mechanisms tested
[ ] Multi-account abuse tested
[ ] Client-side vs server-side enforcement verified
[ ] Findings documented
[ ] Remediation recommendations providedOther measured skills in the registry, with their headline benchmark lift.