← Back to all reports

Unauthenticated Operator API Exposes OTP Dispatcher, Data Exports, and Admin Login

Reported Apr 25, 2026
Severity High
Platform Web / API
Vulnerability Class Missing Authentication for Critical Function (CWE-306)
Target Type National Mobile Carrier (Asia)
Impact Operator OTP dispatcher, subscriber and location exports, admin login reachable unauth

The Risk

The carrier's internal operator console, the same tool staff use to send one-time codes to subscribers and to export customer lists, was reachable from the public internet with no login. A full map of all 170 internal endpoints sat there for anyone to download. While the data export endpoints still required a valid staff token, three administrator login pages, the one-time-code sender, and the internal blueprint of the system were all wide open. It was the equivalent of leaving the staff entrance of the call centre unlocked, with a building floor plan pinned next to the door.

The Vulnerability

The backend ran a Spring Security filter chain to authenticate operator endpoints, but the configuration was selective rather than default-deny. A subset of internal controllers fell outside any matching rule and was therefore handled with no authentication. Sibling controllers on the same host did fall under the chain and correctly returned Access Denied, which is what made the gap unambiguous.

The whole vulnerability was visible in two HTTP requests against the same host:

# Filter chain DOES intercept:
curl -sk https://target/api/users
# 403 "Access Denied"

# Filter chain does NOT intercept:
curl -sk https://target/api/users/csv
# 400 "Required String parameter 'jwtToken' is not present"

The first response is the security filter saying no. The second is the controller's own input validator saying it needed a parameter, which only runs after the filter chain decides to forward the request.

What was reachable unauthenticated

  • The full OpenAPI specification of the operator backend (170 endpoints, no security block defined)
  • An OTP SMS dispatcher used to send one-time codes to subscribers
  • Six data export controllers (subscriber CSV, location history CSV, live SMS transaction stream, SMS transaction file export, contact file download, campaign file download)
  • Three administrator login endpoints (corporate, SMS module, prepaid module)

The Attack

The attack surface was the public host. No proxy, no VPN, and no internal-network position were needed.

Specification disclosure

The /api/api-docs endpoint returned the complete internal contract: every controller, every method, every input parameter, every response shape. The spec also embedded the internal vendor's support email and example phone numbers in the country's national format, confirming this was the production operator console rather than a public-facing surface.

Filter chain reachability proof

For the data export controllers, the controllers themselves verify a signed staff token before returning data. The signed-token check did run (rejecting malformed tokens and explicitly rejecting unsigned tokens with "Unsigned Claims JWTs are not supported"), so a forgery path is not available without the signing secret. The vulnerability proven here is reachability and bypass of the platform-level authentication layer, not full data exfiltration.

OTP dispatcher reachability

The OTP SMS dispatcher returned a Spring MVC error complaining that an accountId body parameter was missing. That error only fires after the filter chain forwards the request, confirming the controller is reachable without authentication. Brute-forcing a valid accountId/jobId pair was out of scope.

Admin login reachability

All three administrator login endpoints accepted unauthenticated POSTs and returned distinguishable responses for "user is locked or not found" versus other states, providing a username-enumeration oracle on internal staff accounts.

The Impact

Direct impact, observed and reproducible:

  • The full internal operator API specification is downloadable by anyone on the internet
  • The filter chain misconfiguration means any future change to the chain rules will silently expose any controller that sits outside an explicit rule
  • The OTP dispatcher controller is reachable without authentication, leaving only a numeric ID guessing barrier between an attacker and the ability to send SMS one-time codes from the carrier's own infrastructure
  • Three administrator login endpoints are reachable for credential-stuffing or username enumeration, with no rate limiting observed at low test volume

Latent impact, gated only by a valid signed staff token: subscriber CSV export, location history export, live SMS transaction stream, SMS transaction file export, contact and campaign file downloads.

Remediation

  • Make the security filter chain default-deny. Replace any default-allow patterns with explicit "authenticated" rules and a small allowlist for liveness and login paths. The current failure mode, where unmatched paths pass through, is the root cause
  • Move the staff token from a query string parameter to the standard authorization header on every data export controller. URL tokens land in proxy logs, browser history, and referrer headers
  • Remove the OpenAPI specification and any developer-facing UIs from production, or restrict them to internal IP ranges, or gate them behind authentication
  • Treat the OTP SMS dispatcher as a privileged operator function. Require an authenticated session with explicit dispatch permission. If the only intended caller is an internal service, require mutual TLS or an internal API key and bind the controller to an internal network
  • Rate-limit the administrator login endpoints and replace differential error messages with a single generic "invalid credentials" response to close the enumeration oracle
  • Audit every path in the OpenAPI specification against the production filter chain configuration. Any path without an explicit rule is a finding even if not listed in this report