← Back to blog

Web App Pentest Methodology: From Recon to Report

NIMR Security Team
penetration testingweb application securityVAPTmethodology

Most teams know what a web application penetration test is. Fewer know what one looks like while it is actually running. This post walks through a recent grey-box engagement for a mid-size fintech client, from kickoff to final report, so you can see what happens at each stage and what a report you can actually act on contains.

The engagement at a glance

Grey-box, five consultant-days, two testers. The client provided low-privileged credentials for the customer portal and its REST API. No source code, no admin access, no architecture documents. That is the setup we recommend for most organizations: it reflects what an attacker can actually reach while giving the tester enough time to go deep.

Scope elementNotes
Customer portalASP.NET Core MVC app behind a WAF, session-cookie auth
REST APISame origin, Bearer tokens, 41 endpoints mapped
Mobile app (out of scope)API endpoints it consumed were in scope

Recon and enumeration

The first two days are reconnaissance. We started with subfinder and the client's own asset inventory to confirm the attack surface, then probed every in-scope host with httpx and fingerprinted the stack with whatweb. Content discovery with ffuf and parameter mining with Arjun filled in the map: 41 API endpoints, three distinct authentication paths, and a handful of endpoints the client's own developers had forgotten existed.

Two things consistently pay off here, even on a short test. Crawl the JavaScript bundles for endpoints and client-side validation logic. And diff the public API against any OpenAPI spec the client provides. Both turn up functionality that never appears in a sitemap.

Authentication and session handling

Authentication testing starts with the login flow and the ways it can be skipped. We tested the password reset for token entropy and expiry (CWE-640), checked error messages for account enumeration (CWE-204), and exercised the lockout mechanism. The lockout was the interesting one: it keyed on the client IP, so rotating an X-Forwarded-For header bypassed it entirely (CWE-307, Improper Restriction of Excessive Authentication Attempts).

The login itself was a plain username/password form, and the session cookie shipped with HttpOnly, Secure, and SameSite=Strict set correctly, which is rarer than it should be. On the API side we checked whether tokens expired, rotated, and stayed scoped to the session they were issued for. Short-lived access tokens with server-side revocation were already in place, so the session layer held up. The bypasses, as usual, were elsewhere.

Authorization: the finding that mattered

[ILLUSTRATIVE] Day three produced the finding that drove the whole report. The API exposed a document download endpoint that took an application ID straight from the URL:

GET /api/v1/applications/{applicationId}/documents HTTP/1.1
Host: portal.fintech-client.example
Authorization: Bearer <low-privileged-user-token>

Swapping one GUID for another returned a 200 with the target application's loan documents. No check that the authenticated user owned the application: a textbook broken object-level authorization (CWE-639), and the top entry in the OWASP Top 10 2025, A01 Broken Access Control. We confirmed the impact with two unrelated test accounts, captured the request/response pair, and scored it High under CVSS 3.1.

This is the finding class we see most often in web and API assessments: not an exotic exploit, just a missing check between two endpoints. It is also the one most likely to be fixed correctly once it is in a report with a clear reproduction, because the fix is a single authorization check, not a rewrite.

The same bug, API-shaped

APIs make BOLA worse because every object is addressable by ID and there is no page chrome to hide behind. The principle is identical for every endpoint that takes an object ID: resolve the object against the caller's permissions, not just against the object's existence. Our API penetration testing checklist covers the API-specific pass in detail.

Input handling and injection

We tested SQL injection with sqlmap against every parameter that touched a database path, including the ones inside JSON bodies, and found nothing: the application used parametrized queries end to end. That is the norm we want to see, and we say so in the report rather than padding it with informational noise.

[ILLUSTRATIVE] The second real finding was server-side request forgery. A payment callback endpoint accepted a callbackUrl in the request body and fetched it server-side:

POST /api/v1/payments/notify HTTP/1.1
Host: api.fintech-client.example
Content-Type: application/json

{ "paymentId": "pay_8f2c", "callbackUrl": "http://169.254.169.254/latest/meta-data/iam/security-credentials/" }

The request reached the cloud metadata endpoint and the response was reflected back to us, a direct path to instance role credentials (CWE-918, A10 in the 2025 Top 10). We stopped at proof and did not pull credentials or touch production data. The fix is an allowlist of callback hosts, a no-credential policy for outbound requests, and the severity is Critical.

Business logic testing

Scanners never find logic flaws because logic flaws are correct behavior with the wrong inputs. We spent the last day on flows: negative quantities, coupon stacking, state transitions, and whether a payment could be replayed. [ILLUSTRATIVE] The client's refund flow accepted a refund larger than the original transaction when the request was crafted directly against the API, a business logic error a UI-only test would have missed (CWE-841, Improper Enforcement of Behavioral Workflow).

The report

Every finding followed the same shape: a verified reproduction, the request and response pair, the CWE and OWASP mapping, a CVSS 3.1 score, the business impact in the client's own terms, and a remediation that names the layer where the fix belongs. Nothing gets reported on a tool scan alone. Tools flag; testers verify.

[ILLUSTRATIVE]

SeverityCountFinding
Critical1SSRF via payment callback
High1Broken object-level authorization
Medium2Lockout bypass, verbose error messages
Low3Missing security headers, informational

Two things separate a usable report from a scan dump: a timeline that puts each finding in context, and a retest policy. We re-tested the Critical and High findings two weeks after the client shipped fixes, and both closed clean.

Takeaways

  • Grey-box with low-privileged credentials gives the best time-to-value for most engagements; black-box is for specific regulatory or threat-model questions.
  • JavaScript bundles and parameter discovery surface more real endpoints than any crawler.
  • Test authorization on every object-ID endpoint. BOLA is the most common critical finding in web and API work.
  • Business logic flows need manual review; scanners will not find them.
  • A report is only as good as its reproduction. Require request/response pairs, CVSS scores, and CWE mappings from any vendor.

Want this methodology applied to your application stack? Request a web & API VAPT or get in touch for a no-obligation scoping call. If you are testing your own APIs in the meantime, the API penetration testing checklist covers the API-specific pass.