Your happy-path tests can all pass while a user can still read another tenant's invoice. A useful security review asks a different question: what happens when the person making a request should not be allowed to do it?
This checklist is for an application you own or have written permission to assess. It gives you a small set of repeatable checks, expected results and evidence to keep. It is a starting point, not a certificate that your application is secure.
This article was prepared with AI assistance.
1. Set up a small, controlled test environment
Use staging with the same authorization rules and relevant configuration as production. Replace real customer records with synthetic data, disable real payments, and route outbound email to a test inbox.
Create these identities:
| Identity | Tenant | Role | Example resource |
|---|---|---|---|
| Alice | Red | Member | Red invoice inv-red-001
|
| Bob | Blue | Member | Blue invoice inv-blue-001
|
| Rita | Red | Admin | Red administration page |
| Logged out | None | None | Public landing page only |
These names and identifiers are invented examples. Substitute records from your own test fixtures. Document which identities may perform each operation before sending requests.
Record the build identifier, environment, date and expected behavior. Keep sessions in separate browser profiles so an accidental account switch does not invalidate a result. Do not put credentials, session cookies or customer data in screenshots you plan to share.
2. Check object access and role boundaries
Open Alice's invoice normally. With Bob signed in, request that same synthetic invoice through the application's own API route. Also check the invoice download and list endpoints. An identifier being difficult to guess does not replace an authorization decision.
Pass: Bob receives the application's defined denial response, and no Red invoice data appears in the body, download, list or preview. A 403 or deliberate 404 can both be appropriate.
Fail: another tenant's data is returned, or the request changes its state. A redirect or status code alone is insufficient evidence; inspect the response body and resulting state.
Next, use Alice to request a Red administrator endpoint. Hiding the button in the browser does not protect the server route. Use harmless read operations first; test writes only against disposable fixtures.
Keep the denial checks as regression tests after fixing a problem. OWASP recommends server-side permission checks for each request and resources, with denial as the default. OWASP authorization guidance.
3. Check what logout actually ends
Sign in to a synthetic account and observe an authenticated request in your browser's network tools. Log out, then repeat the relevant protected request within the test environment.
For a server-session application, the old session should no longer authenticate. For a token-based application, check refresh-token revocation and the intended access-token expiry behavior against your identity provider's documented design. Do not mistake an old page still in the browser cache for a fresh authenticated response.
Pass: server behavior matches the documented session policy; expired or revoked credentials cannot obtain fresh protected data.
Fail: logout only clears the browser's UI while the server continues accepting a session that should have ended.
Also inspect authentication cookies. Secure, HttpOnly and an appropriate SameSite policy matter, but apply them in the context of your login flow and cross-site requirements. Test idle and absolute timeouts. OWASP session-management guidance.
4. Review what the browser and deployment expose
Download your own deployed JavaScript bundles and inspect the build output. Review public source maps, environment-variable usage and accidental deployment artifacts such as .env files or repository metadata.
Pass: server credentials and private keys stay outside public assets; any intentionally public client identifiers have the correct restrictions.
Fail: a private provider credential, database password or server secret is exposed. Remove the exposure and revoke or rotate the credential through its provider. Deleting the file does not make an already leaked secret unusable.
A string that resembles a key needs context: some client identifiers are intentionally public. Do not label every key-shaped value a breach, or paste it into a public issue. OWASP secrets-management guidance.
5. Check input rules on the server
Choose ordinary inputs with explicit business constraints, such as a page size, a quantity or a display name. Submit a negative quantity, an unsupported enum and a value just beyond the documented length limit using your own staging client or API test tooling.
Pass: the server enforces the expected type, range and length, returns a controlled response, and leaves the fixture in a valid state.
Fail: only browser validation enforces the rule, unexpected fields change privileged attributes, or a stack trace reveals internal details.
Validation alone does not prevent every injection issue. Review parameterized database queries and context-appropriate output encoding separately. Treat this exercise as checking a contract, not proving the absence of SQL injection or XSS. OWASP input-validation guidance.
6. Review browser security configuration
Inspect headers on both public pages and authenticated responses. Check for mixed content and confirm that sensitive routes use HTTPS. Review your Content Security Policy for the scripts and resources the application actually needs. Decide which sites, if any, should be allowed to embed the app.
Pass: the policies match the application and are enforced on the relevant responses.
Fail: a policy exists only on the home page, unintentionally allows untrusted framing, or remains in report-only mode when you expected enforcement.
Do not score a JSON API and an HTML page identically. Header requirements depend on what the response does, and a collection of headers cannot repair a missing authorization check. OWASP HTTP-header guidance.
7. Trace one business rule manually
Pick a rule that matters to your product: only an administrator may approve an invitation, a cancelled job must stop, or a draft document must stay private.
Write the rule as a sentence, then follow its full lifecycle with the synthetic identities. Include an interrupted or repeated action. Check the database or a trusted administration view as well as the browser response.
For example, accepting an invitation should not grant a role higher than the inviter is permitted to grant. The invited user, invitation record and resulting membership should agree. Use sandbox integrations and disposable fixtures for workflows that can send messages, charge money or change state.
Record pass only when the resulting state matches the rule. This is manual review of your own application logic. An automated scanner may not understand the intended rule or cover every state transition.
8. Make the result actionable
For each issue, save a redacted request and response, the identity and fixture used, expected behavior, actual behavior, and the affected build. Assign an owner, then repeat the same check after the fix.
Review your application's security logs as well. Failed authorization checks and session events should be attributable without storing passwords, full tokens or unnecessary sensitive data. OWASP logging guidance.
Use a small release record:
Build: staging-release-001
Check: Blue member reads Red invoice
Expected: access denied, no invoice data returned
Actual: [record observed response and state]
Result: pass / fail / inconclusive
Evidence: [private redacted attachment]
Owner: [responsible person]
Retest: [build and result after remediation]
Leave a result inconclusive when setup, missing logs or ambiguous responses prevent a decision. For a failing tenant boundary, exposed server secret or unauthorized privileged action, resolve the issue and verify the fix before relying on that path for real customer data.
Where automated assessment fits
Founder disclosure: I build MyPentest by BugSnaps. It maps verified web applications and runs automated checks with evidence and remediation. Optional test accounts support authenticated testing. The manual workflow above is a general checklist; it is not a claim that MyPentest automates every step or business rule.
MyPentest includes one free assessment per account, with medium and low details. High and critical details, saved history and exports are paid features. It does not replace manual business-logic testing. You can inspect the example report or product page.
What is one authorization or session check you now keep in your release process after finding a bug the hard way?
Top comments (0)