What a penetration test actually finds
Not a list of everything that can go wrong, which nobody reads. These are the classes of finding that decide an engagement: what they look like, why automated tools miss most of them, and what each one is worth to somebody who wants into your system.
Key takeaways
- Access control is the most common serious finding and the least automatable. A scanner cannot know that order 1002 belongs to a different customer than the one logged in.
- Business logic flaws are invisible to tools by definition, because nothing in the request is malformed. The request is legal and the outcome is wrong.
- Input validation is not only injection. Negative quantities, absent upper bounds and type confusion cause real losses without a single quote character.
- Rate limiting is where a defensive control most often becomes an attack, usually because it is keyed on something the attacker supplies.
- Configuration findings are the ones a scanner does find. That is why they should not be what you are paying a tester for.
Broken access control
The most common serious finding in application testing, and the one least likely to be caught by anything you can buy off the shelf. The pattern is always the same shape: the application checks that you are logged in, and forgets to check that the thing you asked for is yours.
A request for an invoice, an order, a document or a user profile carries an identifier. Change the identifier, get somebody else data. It is trivial to exploit and it is trivial to miss, because from the inside the code looks correct: there is an authentication check at the top of the handler and it passes.
Why a scanner does not find it
A tool sees a 200 response with a valid document in it. It has no way to know that the document belongs to somebody else, because it does not know who you are or what you are entitled to. Establishing that requires two accounts, a human who understands the data model, and the patience to try each object against each role. That is the work.
- Object identifiers in the URL, the body or a header that are not checked against the session.
- Functions reachable by a role that should not have them, often because the check lives in the interface rather than the endpoint.
- Identifiers that are sequential, which turns a single flaw into a bulk export.
- Endpoints that check ownership on read but not on update or delete.
The one to test first
If you only have budget to look at one thing, look at every endpoint that takes an identifier and try it with a second account. It is the cheapest test in application security and it finds the most expensive bugs.
Business logic
Flaws where nothing in the request is malformed. Every field is the right type, every value is in range, the session is valid, and the outcome is still wrong. There is no signature to match because the traffic is indistinguishable from legitimate use.
- A price, a discount or a total that the client supplies and the server accepts.
- A multi-step process where a later step can be reached without completing an earlier one.
- A limit enforced in the interface but not on the endpoint behind it.
- A refund, cancellation or transfer that can be replayed because nothing records that it already happened.
- A state transition that can run backwards, turning a completed order back into an editable one.
These are the findings clients most often describe as the reason they paid for a test, because they map directly onto money. They are also the reason scoping matters: a tester who does not understand what your application is for cannot tell the difference between a workflow and a bug.
Input handling that is not injection
Injection gets the attention, and modern frameworks have made the classic cases rarer. What has not gone away is everything else that happens when a field accepts a value nobody expected.
| Pattern | What it looks like | Why it matters |
|---|---|---|
| No lower bound | A quantity or amount that accepts a negative number. | A negative quantity can invert a total. A negative transfer can move money the wrong way. |
| No upper bound | A field that accepts a value far beyond anything real. | Integer overflow, resource exhaustion, or a total that wraps and comes out small. |
| Type confusion | A numeric field that accepts a string, an array or a null. | Downstream code that assumed a number behaves in ways nobody tested. |
| Precision | A currency field that accepts more decimal places than the currency has. | Rounding that consistently favours one side, repeatable at volume. |
| Absent server check | Validation present in the browser and nowhere else. | Every rule you wrote is advisory, because the request can be made directly. |
None of these produce an error a monitoring tool would flag. The request succeeds, the response is a 200, and the damage is in the data.
Rate limiting, and where it turns around
Two findings live here and they are opposites. The first is the absence of a limit: an endpoint that will accept credential attempts, one-time codes or password resets as fast as they arrive. The second is subtler and more interesting, because it is a control that has been implemented and made into a weapon.
A limit keyed on something the attacker supplies can be used to lock out anybody. It is worth its own guide, and it has one: rate limits that lock out your users.
- Authentication, one-time codes and password reset endpoints with no limit at all.
- A limit applied to one route and not to the alternate route that reaches the same function.
- A limit enforced per session, which resets the moment the session does.
- A limit keyed on a value from the request rather than on the caller.
Configuration and exposure
The category a scanner genuinely does cover, and covers well. Expired certificates, weak cipher suites, absent security headers, verbose errors, directory listings, forgotten administrative interfaces, and files that were never meant to be reachable.
These belong in a report and they should be fixed. They should not be most of the report. If a deliverable is mainly configuration findings, what you bought was a scan with a document around it, and our guide to reading a report covers how to tell the difference at a glance.
A useful test of any supplier
Ask what proportion of a typical report is findings a tool could have produced on its own. A supplier who has thought about it will have an answer and will not be embarrassed by it. One who has not will tell you their tooling is proprietary.
Why severity is not the whole story
A score describes a flaw in the abstract. It does not know that the low-severity finding sits on the endpoint your entire customer base authenticates through, or that the high-severity one is behind a feature flag nobody has turned on.
The finding that matters most is usually the one that chains. An information leak that reveals valid identifiers is dull alone and serious next to an access control flaw that consumes them. A tester who writes findings in isolation is describing a system they did not really look at.