- Blog/
The Bugs I Keep Finding in Web App Pentests
Client details change. The bug classes mostly don’t. After enough web application engagements, a shortlist forms of the things that show up often enough to check for by default, before touching anything specific to the app in front of me. None of this is exotic — it’s the boring, recurring stuff that keeps making it into production anyway.
Access control that checks the wrong thing #
The most common finding, by a wide margin, isn’t “no auth check.” It’s an auth check that verifies you’re logged in without verifying you’re allowed to touch this specific object — classic IDOR. A user account that can delete another user’s uploaded files just by changing an ID in the request. A “draft” or “unpublished” resource that’s only hidden by the UI, not by the API — request it directly and it’s right there.
Close behind: function-level authorization gaps. An endpoint meant for an admin role — reordering records, bulk actions, internal management screens — that never actually checks the caller’s role, only that they have a valid session. If your frontend hides a button for regular users, that’s a UX decision, not a security control. The check has to live on the server, on every request, not just in what the UI chooses to render.
File upload validation that trusts the wrong signal #
Almost every app that accepts uploads validates by extension or declared MIME type — both of which the client controls and both of which are trivial to fake. Polyglot files (a PNG that’s also a valid SVG, a JPEG with an embedded payload in its comment field) sail through content-type checks built around the file’s stated type rather than its actual content. Documents disguised as one format while executing as another — a “report.pdf” that’s actually an executable with a renamed extension — are a similarly common miss. The fix isn’t a longer extension blocklist. It’s validating actual file content against the expected format, and never trusting client-declared type for anything that touches storage or gets served back to another user.
Enumeration nobody thought was a vulnerability on its own #
Sequential or predictable IDs in URLs. Login/registration flows that return a different error for “wrong password” versus “no such user.” Neither looks like a critical finding in isolation. Chained together — enumerate valid usernames, then brute-force against the confirmed set, often with no rate limit or lockout in the way — they add up to something that matters. The individual pieces get waved off as “just information disclosure” more often than they should.
Sensitive data one layer more exposed than anyone intended #
Financial or personal data returned in a response payload that’s broader than what the UI displays — the API sends the full object, the frontend just doesn’t render every field, and anyone reading network traffic sees all of it anyway. Sensitive values ending up somewhere they weren’t meant to persist — a cookie, a URL, a client-side log — because it was the easiest place to put them during development and nobody circled back.
The actual takeaway #
None of this requires novel technique. It requires checking the boring things by default: does every object-level request re-verify ownership, not just session validity; does every admin-only action check role server-side; does file validation look at content, not extension; does the API response match what the UI is supposed to show, not everything the backend has. The engagements that come back clean tend to be the ones where someone asked those four questions before shipping, not after a pentest found the gap.
I do web app pentests — access control, file handling, auth, and the rest of the OWASP top 10 territory covered above. If any of these patterns sound familiar in something you’re running: [email protected].