Install
$ agentstack add skill-yaklang-hack-skills-business-logic-vulnerabilities ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
SKILL: Business Logic Vulnerabilities — Expert Attack Playbook
> AI LOAD INSTRUCTION: Business logic flaws are scanner-invisible and high-reward on bug bounty. This skill covers race conditions, price manipulation, workflow bypass, coupon/referral abuse, negative values, and state machine attacks. These require human reasoning, not automation. For specific exploitation techniques (payment precision/overflow, captcha bypass, password reset flaws, user enumeration), load the companion [SCENARIOS.md](./SCENARIOS.md). For the workflow approach itself (modeling → state machine → attack-surface matrix → human judgement) load [METHODOLOGY.md](./METHODOLOGY.md). For the per-module check items load [CHECKLIST.md](./CHECKLIST.md).
Companion files
| File | When to load | |---|---| | [METHODOLOGY.md](./METHODOLOGY.md) | Need the 5-phase workflow, attack-surface 5×N matrix, human-judgement decision tree | | [CHECKLIST.md](./CHECKLIST.md) | Going through a target module-by-module (login / register / payment / IDOR / privacy) and want every line item with why+verify | | [SCENARIOS.md](./SCENARIOS.md) | Drilling deeper into payment precision/overflow, captcha bypass, password reset, enumeration, frontend bypass |
Extended Scenarios
Also load [SCENARIOS.md](./SCENARIOS.md) when you need:
- Payment precision & integer overflow attacks — 32-bit overflow to negative, decimal rounding exploitation, negative shipping fees
- Payment parameter tampering checklist — price, discount, currency, gateway, return_url fields
- Condition race practical patterns — parallel coupon application, gift card double-spend with Burp group send
- Captcha bypass techniques — drop verification request, remove parameter, clear cookies to reset counter, OCR with tesseract
- Arbitrary password reset — predictable tokens (
md5(username)), session replacement attack, registration overwrite - User information enumeration — login error message difference, masked data reconstruction across endpoints, base64 uid cookie manipulation
- Frontend restriction bypass — array parameters for multiple coupons (
couponid[0]/couponid[1]), removedisabled/readonlyattributes - Application-layer DoS patterns — regex backtracking, WebSocket abuse
1. PRICE AND VALUE MANIPULATION
Negative Quantity / Price
Many applications validate "amount > 0" but not for currency:
Add to cart with quantity: -1
Update quantity to: -100
{
"quantity": -5,
"price": -99.99 ← may be accepted
}
Impact: Receive credit to account, items for free, bank transfers in reverse.
Decimal Quantity — "0元购" Case
Real instructor-led case: an e-commerce app accepted fractional quantity because backend trusted client float values:
// Cart item:
{"id": 114016, "skuQty": 0.02}
// Original price ¥500 → final price ¥10
// Variant on a food delivery app:
// FoodNum=0.01 → 68元 商品 实付 0.68元
Why it works: server multiplies unit_price * quantity without enforcing quantity ∈ Z+, so a 2% sliver order pays 2% price but ships the full item. Reproduce by intercepting the cart submit → setting skuQty / FoodNum to 0.02 → finishing checkout.
Drop a Required Field — Free Tier Coercion
Sport activity registration: when paid prizes are involved server returns "payType": "paid"; if the client request is edited to omit prizeIdList entirely, the server falls back to "payType": "free" and creates a successful registration that should have cost money.
// Original
{"prizeIdList": ["6264e6948fe587000113e2d9"], ...}
// Modified — array removed entirely
{"prizeIdList": [], ...}
// Server response:
{"ok": true, "payType": "free"}
This is a parameter-existence trust bug — backend treats "field absent" as "no paid item to enforce", so fix is to require the field and validate its content server-side.
Integer Overflow
quantity: 2147483648 ← INT_MAX + 1 overflows to negative in 32-bit
price: 9999999999999 ← exceeds float precision → rounds to 0
Real case: setting amount=999999999 triggered an overflow path where the system stored 0 as final payable. Always coordinate before triggering overflow tests — they sometimes crash payment services.
Rounding Manipulation
Item price: $0.001
Order 1000 items → each rounds down → total = $0.00
Real "half-price recharge" bug: input ¥0.019 to top-up. The pay gateway charges only ¥0.01 (rounded down to the cent), but the wallet credits ¥0.02 (rounded up). Net gain per cycle is ¥0.01, repeat for free balance growth.
Currency Exchange Rate Lag
1. Deposit using currency A at rate X
2. Rate changes
3. Withdraw using currency A at new rate → profit from rate difference
Free Upgrade via Promo Stacking
Test combining discount codes, referral credits, welcome bonuses:
Apply promo: FREE50 → 50% off
Apply promo: REFER10 → additional 10%
Apply loyalty points → additional discount
Total: -$5 (free + credit)
2. RACE CONDITIONS
Concept: Two operations run simultaneously before the first completes its check-update cycle.
Double-Spend / Double-Redeem
# Send same request simultaneously (~millisecond apart):
# Use Burp Repeater "Send to Group" or Race Conditions tool:
POST /api/use-coupon ← send 20 parallel requests
POST /api/redeem-gift ← same coupon code, parallel
POST /api/withdraw-funds ← same balance, parallel
# If check and update are non-atomic:
# Thread 1: check(balance >= 100) → TRUE
# Thread 2: check(balance >= 100) → TRUE (before Thread 1 deducted)
# Thread 1: balance -= 100
# Thread 2: balance -= 100 → BOTH succeed → double-spend
Race Condition Test with Burp Suite
1. Capture request
2. Send to Repeater → duplicate 20+ times
3. "Send group in parallel" (Burp 2023+)
4. Check: did any duplicate succeed?
Turbo Intruder — Bypassing Per-Number SMS Rate Limit
Real case: when a normal request returns "该号码短时间内申请发送短信次数过多,拒绝发送", sending the same payload with high concurrency through Turbo Intruder defeats the simple counter:
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=30,
requestsPerConnection=10,
pipeline=False)
for i in range(30):
engine.queue(target.req, target.baseInput, gate='race1')
engine.openGate('race1')
Result: the per-phone limiter races and many requests slip through, generating multiple distinct verification codes (a real SMS-bombing case). Root cause: counter increment is non-atomic vs. the read.
Multi-Device Concurrent VIP Subscription
Real case: a service offers first-month-only discount. Open the pay sheet on multiple devices (A, B, C) before any payment finishes, then complete each in sequence. Server only checks "is new user?" at the first request, so all subsequent requests inherit the discount AND the VIP duration stacks.
Normal: 下单 → 支付 → 充值会员 → 第二次下单 → 服务端校验 "已是新人" → 拒绝
Bypass: 设备A: 进入支付页 (锁定优惠资格)
设备B: 进入支付页 (并发锁定)
设备A: 完成支付 → VIP +1月 (优惠价)
设备B: 完成支付 → VIP +1月 (仍按优惠价)
Same trick works on "补差价升级会员" — concurrent top-ups duplicate the duration credit.
Account Registration Race
Register with same email simultaneously → two accounts created → data isolation broken
Password reset token race → reuse same token twice
Email verification race → verify multiple email addresses
Limit Bypass via Race
"Claim once" discounts, freebies, "first order" bonus:
→ Send 10 parallel POST /claim requests
→ Race window: all pass the "already claimed?" check before any write
3. WORKFLOW / STEP SKIP BYPASS
Payment Flow Bypass
Normal flow:
1. Add to cart
2. Enter shipping info
3. Enter payment (card/wallet)
4. Click confirm → payment charged
5. Order confirmed
Attack: Skip to step 5 directly
POST /api/orders/confirm {"cart_id": "1234", "payment_status": "paid"}
→ Does server trust client-sent payment_status?
Multi-Step Verification Skip
Password reset flow:
1. Enter email
2. Receive token
3. Enter token
4. Set new password (requires valid token from step 3)
Attack: Try going to step 4 without completing step 3:
POST /reset/password {"email": "victim@x.com", "token": "invalid", "new_pass": "hacked"}
→ Does server check that token was properly validated?
Or: Try token from old/expired flow → still accepted?
2FA Bypass
Normal flow:
1. Enter username + password → success
2. Enter 2FA code → logged in
Attack: After step 1 success, go directly to /dashboard
→ Is session created before 2FA completes?
→ Does /dashboard require 2FA-complete check or just "authenticated" flag?
Filter Path Truncation Bypass — ..// and ;
Real case from a Java Web class audit: a manually-implemented Servlet Filter checks login by inspecting the URI string. Two reliable bypasses:
Path-traversal truncation (../):
Protected: http://target/FilterDemo/index.jsp → 302 to /login
Bypass: http://target/FilterDemo/../../index.jsp → 200 (filter sees "../../", URL parser collapses)
Semicolon truncation (;):
Protected: http://target/admin/doLogin.action → 302 to /login
Bypass: http://target/;/admin/doLogin.action → 200
^
Servlet container treats segment after ; as "path parameter",
filter that uses request.getRequestURI() sees "/;/admin/doLogin.action",
doesn't match its protected-prefix "/admin/", lets the request through,
but the dispatcher then routes to the real /admin/doLogin.action handler.
Fix: never use request.getRequestURI() for security checks; use request.getServletPath() which is the normalized servlet-mapped path:
// Vulnerable
String uri = request.getRequestURI(); // /;/admin/doLogin.action
// Safe
String path = request.getServletPath(); // /admin/doLogin.action
When auditing Java code, grep for request.getRequestURI() paired with Filter/startsWith/indexOf("/admin") patterns — those are immediate red flags.
Real-Name Verification Replay-To-Reset
Fraudulent path that deliberately fails real-name authentication to reopen the editing flow:
1. Submit real-name auth with intentionally wrong cardNumber
→ server returns "code:200, msg:success, ok:true" but flow shows "驳回 / 等待审核"
2. Because the server marks state as "rejected" but doesn't lock the user, the UI lets the
account go back into the "edit identity" state
3. Now resubmit with another (possibly stolen) identity
→ real-name binding repeats indefinitely, defeating anti-addiction lock and enabling account resale
Defense: rejected real-name submissions must lock the account / require human review, not loop back to the editor.
Shipping Without Payment
1. Add item to cart
2. Enter shipping address
3. Select payment method (credit card)
4. Apply promo code (100% discount or gift card)
5. Final amount: $0
6. Order placed
Attack: Apply 100% discount code → no actual payment processed → item ships
4. COUPON AND REFERRAL ABUSE
Coupon Stacking
Test: Can you apply multiple coupon codes?
Test: Does "SAVE20" + promo stack to >100%?
Test: Apply coupon, remove item, keep discount applied, add different item
Referral Loop
1. Create Account_A
2. Register Account_B with Account_A's referral code → both get credit
3. Create Account_C with Account_B's referral code
4. Ad infinitum with throwaway emails
→ Infinite credit generation
Coupon = Fixed Dollar Amount on Variable-Price Item
Coupon: -$5 off any order
Buy item worth $3, use -$5 coupon → net -$2 (credit balance)
5. ACCOUNT / PRIVILEGE LOGIC FLAWS
Email Verification Bypass
1. Register with email A (legitimate, verified)
2. Change email to B (attacker's email, unverified)
3. Use account as verified — does server enforce re-verification?
Or: Change email to victim's email → no verification → account claim
Password Reset Token Binding
1. Request password reset for your account → get token
2. Change your email address (account settings)
3. Reuse old password reset token → does it still work for old email?
Or: Request reset for victim@target.com
Token sent to victim but check: does URL reveal predictable token pattern?
OAuth Account Linking Abuse
1. Have victim's email (but not their password)
2. Register with victim's email → get account with same email
3. Link OAuth (Google/GitHub) to your account
4. Victim logs in with Google → server finds email match → merges with YOUR account
Cookie Replacement — Horizontal/Vertical Privilege Escalation
The textbook IDOR demo from the audit videos:
1. Login as super-admin → capture request, copy Cookie (JSESSIONID/Token)
2. Logout, login as plain user → capture another request to the SAME endpoint
3. Replay the plain-user request, but swap the Cookie value with the admin's token
4. If the response returns admin-only data → vertical escalation
If it returns another-user's data → horizontal escalation
A common companion bug: /oa/emp/list returns HTTP 302 to /login when no cookie, but 200 with full data when any plain-user cookie is sent — meaning the only check is "logged in?", not "authorized for this endpoint".
Permission Residue from Database Inconsistency
A subtle case from the second audit class: the admin UI shows that role X has had permission user:list revoked, but querying the SQL data:
SELECT * FROM sys_menu WHERE role_id = 2;
-- two rows for the same menu_id "user:list"
The UI's "remove permission" only deleted ONE row; the duplicate row keeps the API accessible. Verify by:
SELECT menu_id, COUNT(*) FROM sys_menu GROUP BY menu_id, role_id HAVING COUNT(*) > 1;
Lesson: when a UI says permission revoked but API still works → check the underlying RBAC table for duplicates / orphaned grants.
Weak-Random Password Reset Token
PHP / legacy stack on Windows uses rand() whose RAND_MAX = 32768. If a reset link uses /resetpassword.php?id=md5(rand()), the entire keyspace is precomputable:
$a = 0;
for ($a = 0; $a ` — when one returns a valid reset page you can change the victim's password. Audit any token generation that ultimately calls `rand()`, `mt_rand()` (without seeding), `Random()` (default seed in C#), etc.
---
## 6. API BUSINESS LOGIC FLAWS
### Object State Manipulation
order.status = "pending" → PUT /api/orders/1234 {"status": "refunded"} ← self-trigger refund → PUT /api/orders/1234 {"status": "shipped"} ← mark as shipped without shipping
### Transaction Reuse
- Initiate payment → get transaction_id
- Complete purchase
- Reuse same transaction_id for second purchase:
POST /api/checkout {"transactionid": "USEDTX", "cart": "new_cart"}
### Limit Count Manipulation
Daily transfer limit = $1000 → Transfer $999, cancel, transfer $999 (limit not updated on cancel) → Parallel transfers (race condition on limit check) → Different payment types not sharing limit counter
### Java Web "No Filter, No Spring Security" Anti-Pattern
Audit-friendly tell: a Spring Boot project that does **NOT** include `spring-boot-starter-security` and has zero `Filter` classes. This means every controller is wide-open for `guest` unless the developer manually checked the session in each method. Reproduce:
```bash
# Inside the source tree
find . -name "*.java" -exec grep -l "Filter" {} \; # likely empty
find . -name "*.java" -exec grep -l "@PreAuthorize\|@Secured" {} \;
If both are empty, expect almost every API to be unauthorized. From the audit demo:
public Result score(@RequestParam("userId") Integer userId) {
Score score = scoreService.selectScore
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [yaklang](https://github.com/yaklang)
- **Source:** [yaklang/hack-skills](https://github.com/yaklang/hack-skills)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.