Unauthenticated Endpoint

ID

unauthenticated_endpoint

Severity

high

Remediation Complexity

medium

Remediation Risk

high

Remediation Effort

medium

Family

API2:2023 - Broken Authentication

CWE

CWE-306

Resource

authentication

Language

any

Description

Reports HTTP endpoints that declare no authentication requirement. The endpoint inventory carries each endpoint’s authentication evidence (annotations, middleware chain, OpenAPI security: block, framework-level filters); when none of those are present, and the endpoint’s path is not in the allowlist of legitimately public routes (/health, /metrics, /actuator/, /.well-known/, …), the endpoint is flagged.

This is the canonical OWASP API2:2023 — Broken Authentication signal at the endpoint-shape level.

The tier reflects the evidence, not the impact. Every finding is an endpoint that provably declares no authentication; a multi-signal classifier weighs what corroborates that it ought to, and returns one of three verdicts:

  • auth required — several independent signals agree: it returns data classified as sensitive, accepts sensitive input (a query parameter or body; a path parameter only addresses the resource), sits on a sensitive-resource path (/admin, /users, /payments, …), or mutates state. Reported at the severity above when the endpoint is state-changing, one rank lower when it is read-only — an anonymous POST hands a stranger a state change, an anonymous GET exposes data.

  • undetermined — nothing corroborates either way. Reported at info: real, but informational, and it does not raise the project’s risk level. Confirm the exposure is intended and add the path to publicPaths to silence it.

  • anonymous by design — login, signup, OAuth callback, webhook receiver. Not reported as a finding.

An endpoint whose controller serves the same resource behind authentication too — the same path with one more literal segment, such as /cart/{code}/payment/init beside /auth/cart/{code}/payment/init — is that route’s guest variant. Leaving it open is a decision rather than an omission, so it is reported at info and names the authenticated route.

A decision not to report is itself recorded, at info, so it can be audited — see reportSuppressions under Configuration.

Rationale

An endpoint that does not require authentication is reachable by any client on the network, with no audit trail tied to a user identity. For endpoints handling business data this is a direct path to enumeration, scraping, abuse, and data exfiltration — every public, unauthenticated finding is reachable from the internet the moment the service is exposed.

Unauthenticated endpoints often slip in unintentionally — a missing @PreAuthorize, a route added before the auth middleware was registered, a removed annotation during a refactor, an OpenAPI spec where the global security: was overridden to security: [] for a single operation and never restored. Static endpoint review is the only reliable way to surface them before a release.

Remediation

Add an authentication requirement at the endpoint, controller, or service level using the framework’s standard mechanism — annotation, middleware, OpenAPI security: block, or a global filter that denies-by-default and only allow-lists explicit public routes.

  • Spring / Spring Boot: @PreAuthorize, @Secured, @RolesAllowed, or method security in SecurityConfig.

  • ASP.NET Core: [Authorize] on the controller or action.

  • JAX-RS: @RolesAllowed / @DenyAll / SecurityContext check.

  • Express / NestJS / Fastify / Koa / Hono: an authentication middleware (passport, express-jwt, NestJS Guard, …) registered before the handler.

  • FastAPI / Flask: a Depends(…​) / before_request authentication callback.

  • OpenAPI / Swagger: a security: requirement on the operation or globally.

If the endpoint is genuinely public (health checks, marketing landing pages, OAuth callback URLs, …), add its path to the detector’s publicPaths allowlist so the finding stops firing.

Configuration

The detector accepts two configurable parameters:

  • publicPaths — list of Ant-style glob patterns whose endpoints are exempt. Built-in defaults (/health, /metrics, /actuator/, /.well-known/) always apply; entries here are added on top.

  • reportSuppressions (default true) — whether a decision not to report is emitted as a finding of this detector at info, carrying suppressed_by and suppression_evidence (what matched and how it resolved). info keeps it out of the default view and out of the project’s risk level, so auditing the decision cannot bury the confirmed findings. Set it to false in a large repository where the informational volume is unhelpful.

suppressed_by takes one of three values, which is what to filter on:

  • unresolved_route_stub — the endpoint is a URL-configuration entry whose handler discovery could not resolve, so its only location is the route.

  • public_path_allowlist — the path matched a pattern on publicPaths (the evidence names the pattern, and whether it is built-in or configured).

  • anonymous_by_design — the classifier judged the endpoint a login, signup, OAuth callback or webhook receiver (the evidence carries its reasons and score breakdown).

Unless your project has additional well-known public paths, you typically do not need to configure this detector.

References

© 2026 Xygeni. All rights reserved