Website problems
Publicly readable API endpoint
An API endpoint that returns data to a request carrying no credentials is public, whatever the intention was. This is correct for a price list or a public catalogue and wrong for anything about a person or about your operations. The finding is not that such endpoints exist — most sites have several legitimately — but that the list needs going through, because the ones nobody meant to publish look identical from outside.
How an endpoint becomes public without a decision
It was built for an internal screen, where authentication was handled by the surrounding application and never applied to the route itself.
It was public deliberately at some point, and the data it returns grew to include fields that were not public when the decision was made.
An authentication middleware is applied per route group, and a route added later landed outside the group.
A framework upgrade reset a configuration, re-enabling default routes that were previously disabled.
An older version of the API was left running after a rewrite, with whatever access rules it had at the time.
Why an empty list is not access control
An endpoint answering 200 with an empty array to an anonymous request looks harmless and frequently is not.
It often means the query ran with no user context and matched nothing, rather than that access was refused.
Adding a parameter — an identifier, a filter, a pagination offset — can then return the full set.
The distinction matters because a 200 with nothing in it reads as safe in a report, and a 401 reads as refused.
So the useful test is not whether data came back but whether the endpoint refused, and only the second is access control.
What makes an endpoint's data non-public
Anything identifying a person: names, addresses, email addresses, telephone numbers, account identifiers.
Anything about a transaction: orders, invoices, bookings, payment references.
Anything about your operations: stock levels, internal statuses, staff names, pricing rules.
Sequential identifiers, which turn a single accessible record into an enumerable set.
Fields nobody notices, such as an internal note or a status flag serialised alongside the data the screen displays.
How to close one without breaking the front end
Find out what calls it. The site's own scripts are the first place to look, and the server access log is the authoritative one.
Require authentication on the route, and confirm the front end sends a credential — many do already and were simply not being checked.
Where the data really must be public, reduce what is returned rather than the access: serialise only the fields the public screen needs.
Return 401 rather than an empty result, so the behaviour is unambiguous to you and to everything else.
Check the older versions of the same endpoint, since closing the current one leaves the previous one answering.
How to check it yourself
Open a private browser window, load a page that uses the API, and read the network panel for the request URLs.
Request those URLs directly with no cookies or headers — `curl` with nothing added is the right client for this.
Read what comes back rather than only the status: a 200 with data is the finding, a 401 or 403 is the endpoint working.
Repeat for the conventional paths a framework serves by default, which are frequently forgotten.
Do the same against any older version prefix that still answers.
How VeriFixScan detects it
`api.endpoint.public_data` lists the endpoints that returned data without any authentication, which is this problem directly.
`api.endpoint.protected` lists the ones that refused, reported as the expected behaviour rather than as a finding.
`api.surface.detected` builds the inventory from paths the site references plus a fixed set of conventional ones — nothing is enumerated or brute-forced.
`api.transport.https` verifies each observed endpoint is served over HTTPS.
`auth.login.public` establishes whether the site has an authenticated area at all, which frames how seriously a public endpoint reads.
What the scan cannot tell you
Whether an endpoint was meant to be public. Only you know which of them corresponds to a decision.
Whether an endpoint not referenced anywhere exists, since nothing is enumerated and no wordlist is used.
What an authenticated request would return, because no credential is ever supplied.
Whether a parameter would widen an empty response, because no parameter is fuzzed.
Which makes the output an inventory to review rather than a verdict, and the review is the part only you can do.
Frequently asked questions
- Is a public API endpoint automatically a problem?
- No. Public read access is correct for public data, and it is reported as an observation. The work is going through the list and confirming each entry was meant to be on it.
- My endpoint returns an empty array without a token. Is that safe?
- Not necessarily. That often means the query ran with no user context rather than that access was refused. Adding a parameter can return the full set. Return 401 instead.
- Do you try to find hidden endpoints?
- No. Only paths the site itself references plus a fixed list of conventional ones are requested. There is no wordlist, so an unreferenced endpoint is not discovered.
Sources
Related
VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.
Scan a website