11 August 2026

How to Test Business Logic Vulnerabilities in a SaaS Application

How to Test Business Logic Vulnerabilities in a SaaS Application
12 min. readBy Borg

Automated security tools are good at finding classes of vulnerabilities they know how to recognise: vulnerable dependencies, injection patterns, exposed services and malformed input. They struggle when the vulnerability is a violation of a rule specific to your application. A generic scanner does not inherently know that a user should not be able to downgrade from the Enterprise plan while keeping Enterprise-only features. The API response can look completely valid while the business rule has been broken. That gap is where some of the most consequential SaaS vulnerabilities live, and it is one of the hardest areas to test systematically.

To effectively test business logic vulnerabilities, you must move beyond generic input validation checks. You need a methodology that maps the specific invariants of your application and systematically attempts to break them. This guide provides a step-by-step offensive testing framework designed for modern SaaS environments. It is designed for senior security engineers who need to verify auth flows, billing logic, and tenant isolation in modern B2B SaaS environments. Everything below assumes you are testing an application your organisation owns or is authorised to test. Before you begin, set up a dedicated staging environment and at least two test accounts at different permission levels, in two different organisations, so object-level authorisation can be checked properly.

Step 1: Map Your Application's Business Rules and Invariants

You cannot test business logic vulnerabilities if you do not understand the underlying state machine. Every SaaS application has a set of unwritten rules that govern how data moves and who can trigger specific actions. This mapping process represents a critical business logic data validation phase. Your first task is to translate these rules into a map of invariants: things that should never be possible regardless of the input.

Start by documenting the primary workflows. In a B2B SaaS platform, these usually include seat management, API key generation, and data export. For each workflow, identify the requirements. If a rule says a user needs the Admin role to export data, that is an invariant. If the rule says a user can only invite five teammates on the Pro plan, that is another. Write these down. Do not rely on your product documentation because it often describes how the app is supposed to work, not how the API actually behaves under pressure.

Use an intercepting proxy to observe how the application handles these rules at the network level. Look for the specific parameters that enforce these logic gates. If a seat limit is enforced by a client-side check, the API might still accept the request. This is why mapping is the most technical part of the process. You are looking for the discrepancy between what the UI shows and what the backend allows.

Focus on the transitions between states. A transition from an Unpaid state to a Paid state is a high-value target. If you can move a resource into a Paid state without a corresponding success signal from a payment processor, you have found a business logic flaw. Most teams fail here because they treat the app as a collection of endpoints rather than a sequenced state machine. Mapping the sequence is the only way to find where the logic breaks.

Step 2: Identify the High-Risk Surfaces (Auth, Billing, Tenant Isolation, Approvals)

Not all logic is created equal. A bug in the profile picture upload logic is annoying. A bug in the tenant isolation layer is catastrophic. You must prioritise your testing efforts on the four surfaces that carry the most risk for B2B SaaS companies: authentication flows, billing and subscription management, multi-tenant data isolation, and administrative approval workflows.

Authentication flows are more than just login screens. They include password resets, multi-factor authentication (MFA) enrolment, and Single Sign-On (SSO) handshakes. A common logic flaw involves the MFA skip: an attacker triggers a password reset, changes the password, and the system automatically logs them in without asking for the MFA token that was previously active. This bypasses the security intent of the MFA feature entirely.

Billing logic is the most overlooked area in traditional pentesting. Scanners rarely have the context to test if a user can manipulate the quantity of items in a cart to a negative number or if they can apply a 100% discount code multiple times. In a SaaS context, look for the credit system. If your app uses a credit-based model for AI tokens or API calls, test whether the balance check happens before or after the resource-intensive action is performed. If it happens after, an attacker can spin up thousands of concurrent requests to drain resources before the balance hits zero.

Tenant isolation is the core requirement of SaaS. You must verify that a request intended for Organisation A cannot access resources belonging to Organisation B. This is often implemented via a tenant ID in the header or the URL. Test this by capturing a valid request from User A, then replacing the session token with User B's token while keeping User A's tenant ID. If the request succeeds, your isolation logic is broken. This is a classic Broken Object Level Authorization (BOLA) issue, which remains a primary concern for modern API security.

Step 3: Build Abuse Cases From Your Invariants

Once you have mapped your invariants and identified high-risk surfaces, you must build specific abuse cases. An abuse case is a structured plan to break a business rule. It differs from a standard test case because it ignores the intended user path entirely. If the intended path is A to B to C, the abuse case asks what happens if you go from A directly to C, or if you repeat B ten thousand times in a second.

Create a matrix of your invariants. For an invariant like "A user cannot view another user's private data", the abuse cases should include: 1. Changing the ID in the URL. 2. Changing the ID in the JSON body. 3. Accessing the resource via a public API endpoint that lacks authorisation checks. 4. Accessing the resource via a legacy version of the API (v1 instead of v2). This systematic approach ensures you do not just check the obvious paths.

If a SaaS platform offers a 14-day trial, an invariant might be: “An account cannot retain paid functionality after its trial entitlement expires.” Test the different paths that affect that entitlement: cancelling and restarting the trial, creating additional workspaces, accepting invitations into another tenant, changing plans near expiration, replaying trial-creation requests, and sending requests directly to paid-only endpoints after the UI reports the trial as expired. The interesting bugs usually appear where two legitimate workflows interact in a way nobody intended.

Use your understanding of the tech stack to inform these cases. If approvals are processed asynchronously, test whether the backend still validates the actor, resource and expected state when the approval is eventually processed. Security checks performed only when the workflow is initiated can become ineffective if a queued or delayed action is later executed against state that has changed.

Step 4: Test Workflow State and Request Sequence

Modern SaaS applications are essentially large state machines. A user moves from a draft state to a pending state to a published state. Vulnerabilities occur when these transitions are not strictly enforced. A critical area of concern involves the potential circumvention of established workflows. You must test if steps can be skipped, reordered, or replayed to achieve an unauthorised outcome.

The most common workflow attack is the forced browsing or step-skipping attack. In a multi-step registration flow, Step 1 might be email verification, Step 2 might be payment, and Step 3 might be account creation. If an attacker can navigate directly to the Step 3 URL or POST to the Step 3 endpoint without a valid session token from Step 2, the billing logic is bypassed. You test this by completing the workflow legitimately, capturing the final request, and then attempting to replay that request in a fresh, unauthenticated session.

Another critical area is the replay attack on one-time actions. If an application allows a user to claim a reward or use a coupon, that action should be idempotent or strictly limited. Test this by sending multiple identical requests in a very short window (a race condition) to see if the system processes the action more than once before the database updates the state. If you can use a single-use coupon code five times because the validation and the consumption are not an atomic operation, you have a logic flaw.

Parameter pollution and integrity checks also fall under sequence testing. In some cases, a parameter from an earlier step is cached and used in a later step. If you can inject a different parameter in a later request that overrides the initial validated value, you can break the logic. In a fintech app, if the interest rate is calculated in Step 1 and passed as a hidden field to Step 2, you must attempt to modify that field before the final submission. If the backend does not re-calculate or verify the signature of that data, the logic is vulnerable.

Step 5: Test Multi-Tenant Isolation and Object-Level Authorisation

In a B2B SaaS environment, the most critical business logic is the code that ensures Tenant A cannot see Tenant B's data. This is not just about authentication. It is about authorisation at the object level. Every single API request that takes an ID as a parameter is a potential failure point. You must test these by attempting to access, modify, or delete objects belonging to a different organisation using a valid session from your own.

Start with the most obvious IDs: those in the URL. If the endpoint is /api/v1/org/123/projects/456, change 123 to the ID of another tenant. Then try changing 456 to the ID of a project belonging to that tenant. If the API returns the data, the authorisation check is likely only happening at the Org level and not the Project level. This is a common shortcut developers take to save on database queries, but it creates a massive security hole.

Move beyond the URL and check the request body and headers. Many modern APIs use custom headers like X-Org-ID or X-Tenant-ID to route requests. If the backend trusts this header without verifying it against the user's session token, an attacker can simply swap the header value to impersonate another organisation. This is the class of change Borg's Gungnir is pointed at: it reviews pull requests touching auth, access control and isolation, so a header the backend trusts too readily gets raised on the diff rather than after release.

Finally, test for vertical privilege escalation within a tenant. If a standard user can access the /api/v1/admin/settings endpoint by simply knowing the URL, the business logic governing roles is failing. A common mistake is to hide the Admin button in the UI while leaving the API endpoint completely unprotected. You must verify that every administrative action requires a specific permission check on the backend. A missing link in the UI does not mean the endpoint is secure. Offensive testing requires you to act as if the UI does not exist.

Why Scanners Miss Business Logic Bugs: and What to Use Instead

Traditional security tools are designed to find known patterns. A logic bug is, by definition, a unique flaw in the way your specific application was built. Static analysis (SAST) tools see the code but lack the execution context to know if a logic gate is correct. Dynamic analysis (DAST) tools see the execution but lack the business context to know if a 200 OK response is actually a security failure. Your scanner didn't find it because it wasn't looking for the violation of a business rule.

ApproachGood atWhere it stops
SASTKnown-bad patterns in source, cheap enough to run on every buildDetermining whether application-specific behaviour violates the intended business rules
DASTCrawling and fuzzing a running applicationWorkflows that require product-specific context, complex state or relationships between multiple users and tenants
Manual testing against invariantsReasoning about what should be impossibleExpensive to repeat continuously and constrained by the time and scope of each engagement
Code-informed offensive testingUsing the repository to decide which paths are worth attacking, then attempting themStill depends on the invariants being right. Nothing finds a rule nobody wrote down

Instead of relying on annual PDFs from a point-in-time pentest, engineering teams need to integrate offensive testing into their daily workflow. A vulnerability in your auth flow is a high-priority bug that should be treated like a breaking production error. Borg reports findings with reproduction steps attached, so a developer sees the path that was actually taken rather than a pattern that matched. Proving the path before reporting it is what changes the shape of the queue. Shifting to a continuous offensive model closes the gap between code changes and security verification. Findings then collect in Odin, where they are tracked and retested once a fix lands.

Frequently asked questions

Can automated scanners test business logic vulnerabilities?

Not on their own, because they lack the context. A scanner does not know your seat limits, your approval chain or which records a given role should reach, so a request that breaks one of those rules still returns a normal response and passes. Pattern-based tooling remains worth running for the class of problem it does cover; it just cannot tell you whether a rule was violated. See what continuous pentesting means for how the two fit together.

How do you test for IDOR in a SaaS application?

Create two accounts in two different organisations, then take a valid request from the first and replay it against the second organisation's object ids, changing them in the URL, in the JSON body, and in any tenant header the API accepts. Do the same against older API versions still in service. If any of those return data, the authorisation check is not happening at the object level.

Does OWASP WSTG 4.10 cover all business logic bugs?

No. It is a strong framework for testing business logic, covering areas such as data validation, forged requests, integrity checks, process timing, function-use limits, workflow circumvention, application misuse and payment functionality. But it cannot enumerate the rules unique to your product. You still need to identify your own invariants and build abuse cases around them.

Where should a small team start?

With tenant isolation, because it is the one failure that exposes another customer's data rather than your own. Write down the rule, create the second organisation, and try to cross the boundary on every endpoint that takes an id. That exercise alone usually surfaces whether authorisation is being enforced per object or only at the edge.

Conclusion

Business logic vulnerabilities sit in an awkward place. They are not pattern matches, so signature-based tooling does not see them, and they are not exotic, so they turn up in ordinary features. A broken tenant boundary or a bypass in a billing workflow lives in the space between what your features do and what you assumed they would do. Testing them requires a methodical approach that prioritises invariants over generic inputs.

A point-in-time pentest can tell you where the application breaks today. It cannot continuously verify every auth change, billing feature or new API route you ship afterwards. If your application changes every week, some part of your security testing should move at the same speed.

Book a walkthrough with Borg to see how continuous offensive testing works against your own auth flows, APIs and tenant boundaries, with validated findings delivered into the same workflow your engineers already use.

Frequently asked questions

Can automated scanners test business logic vulnerabilities?
Not on their own, because they lack the context. A scanner does not know your seat limits, your approval chain or which records a given role should reach, so a request that breaks one of those rules still returns a normal response and passes. Pattern-based tooling remains worth running for the class of problem it does cover; it simply cannot tell you whether a business rule was violated.
How do you test for IDOR in a SaaS application?
Create two accounts in two different organisations, then take a valid request from the first and replay it against the second organisation's object ids, changing them in the URL, in the JSON body, and in any tenant header the API accepts. Do the same against older API versions still in service. If any of those return data, the authorisation check is not happening at the object level.
What is the difference between BOLA and IDOR?
They describe the same failure. Broken Object Level Authorization is the term OWASP uses in its API Security Top 10; Insecure Direct Object Reference is the older name for it. Both mean the application resolved a record by its identifier without confirming the caller was entitled to that record.
Does OWASP WSTG 4.10 cover all business logic bugs?
It is a good foundation and worth working through: it covers data validation, workflow circumvention, integrity checks and function misuse. It is a methodology rather than a list of your bugs, though. The logic specific to your own product, the invariants nobody wrote down, is the part you have to map yourself before any framework helps.
Where should a small team start with business logic testing?
With tenant isolation, because it is the one failure that exposes another customer's data rather than your own. Write down the rule, create a second organisation, and try to cross the boundary on every endpoint that takes an id. That exercise alone usually reveals whether authorisation is enforced per object or only at the edge.

Borg on
Social Media

Borg specializes in securing complex, high-risk digital systems.