Home/Journal/Pattern
Patternauthenticationmicroservicesserverless

The Sibling Service That Skipped Authentication

The main app enforces auth well, but a sibling service on the same estate does not. Here is why the side door stays unlocked and how to close it.

Rahul Dharan··8 min read

What this is

An unauthenticated sibling service is a second service, running on the same estate as a well-defended application, that enforces no authentication of its own. The main product does everything right - real login, sessions, a gateway that checks every request. Then a serverless function, a microservice, a background-job engine, or a model-server sits next to it on the same infrastructure, internet-reachable, asking nobody for a credential. The front door is locked and monitored. A side door on the same building stands open.

This is one of the most reliable findings we produce, because the security of the main app actively hides it. A team that has hardened its front door reasonably believes the building is secure. The sibling never got the same attention because it was never thought of as a door.

Why it keeps happening

Security review follows where the team expects attackers to arrive, and that is the user-facing app. The login flow gets threat-modeled. The gateway gets an auth filter. The session handling gets tested. All of that attention concentrates on the one surface everyone agrees is exposed.

The supporting services are built under a different mental model. A serverless function gets deployed to do one job and defaults to public because that was the quickest way to make it callable. A microservice gets mounted into the mesh but not behind the gateway’s auth filter, because it was “internal.” A GPU model-server or a job engine gets stood up beside the app to serve it, and the team assumes the app in front is the only caller. Each of these is a reasonable local decision. Together they produce a building with one guarded entrance and several unguarded ones.

The most common and most dangerous variant is the front-end assumption: the single-page app enforces login, so the team treats that login as the gate for the whole system. But the backend the front-end talks to is often directly reachable, and it runs with auth disabled because “the front-end already checks.” An attacker never touches the front-end. They call the backend directly, and the only lock in the system is the one they walked around.

How the attack works

Finding a sibling service is enumeration, not exploitation:

  1. Map the estate. Subdomains, API hosts, function URLs, and the network calls the front-end makes all point at services beyond the main app. Black-box, from outside, this surface is visible.
  2. Probe each one for its auth posture. Send a plain request to each service with no credential. The main app returns 401. Somewhere on the estate, a sibling returns 200 and does its job.
  3. Call the sibling directly. Whatever that service does - process a payment, run a model, drive a maintenance action, return records - the attacker now does it without ever authenticating, because the only authentication in the system lived in a front-end they skipped.

There is no bypass and no clever payload. The attacker simply talks to the service that never asked them to log in.

What it looks like in the wild

We have found this across companies that share nothing but the shape of their infrastructure.

The consistent theme: the strength of the main app is exactly what keeps the sibling out of scope in everyone’s mind, right up until someone enumerates the estate instead of the app.

How to tell if you are exposed

A short self-check:

  1. Enumerate every internet-reachable service on your estate, not just the main app - subdomains, function URLs, microservice hosts, model-servers, job engines, admin and utility routers.
  2. Send each one a request with no credential. Anything that returns 200 and does real work is an open door, regardless of how well the front door is locked.
  3. For every backend your front-end talks to, ask whether it is directly reachable. If it is, test it without going through the front-end. If it answers, the front-end’s auth is protecting nothing.
  4. Read your gateway config for services mounted outside the auth filter, and your serverless functions for any set to public. Look specifically for authentication that was commented out or “temporarily” disabled.

How to fix it

The takeaway

Attackers do not attack your app; they attack your estate. A hardened front door counts for nothing if a serverless function, a model-server, or a maintenance router on the same infrastructure answers without a credential. Enumerate every service, deny by default, and treat “the front-end checks it” as no protection at all. See this pattern in the field in No Lock on the GPU and its siblings.

Frequently asked

What is an unauthenticated sibling service?
It is a service on the same estate as a well-secured application that itself has no authentication. The main app enforces login correctly, but a serverless function, microservice, background-job engine, or model-server nearby is internet-reachable with no auth. The front door is locked; a side door on the same building is open.
Why does the main app get secured but the sibling does not?
Teams concentrate security review on the user-facing app because that is where users and attackers are assumed to arrive. Supporting services get stood up quickly, inherit no gateway auth filter, and are assumed to be internal or protected by the front-end. On a reachable host, that assumption is the vulnerability.
Does front-end authentication protect the backend?
No. If the backend is directly reachable, an attacker skips the front-end entirely and calls the backend without ever logging in. Front-end auth protects the front-end. Every service must enforce its own authentication, or sit behind a gateway that enforces it for every route.

This is one finding from a harness that runs continuously. See how Greywatch finds, proves, and fixes them.

How it works →