NewApp Monitoring is liveSign up free
AgentbeamBeta
Course outline

Learn / Level 2 / lesson 4

Broken authentication

How a login check can be skipped entirely, the common shapes of the flaw, a real exploited SharePoint case, and how to build and test a check that cannot be bypassed.

8 min read · Yash Thakker · updated 2026-10-24

broken authentication · authentication bypass · CWE-287 · web security · case study

A locked front door with an unlocked side door beside it that leads to the same room

What you will learn

  • Name the common shapes of an authentication bypass
  • Explain why every protected path needs the check on the server
  • Read a real CWE-287 record and say what it tells you
  • Write a deny-by-default check and a test that tries to skip it

Before this: Sessions, cookies and tokens

Imagine a bank vault with a thick door, a combination lock and a guard, and a staff entrance round the back that nobody remembered to lock. The vault is not weak; the building is. is that: the login mechanism is fine, but the system can be made to treat someone as logged in without it. Because everything after login trusts the answer, one skipped check undoes every protection behind it.

What the check must guarantee

A correct authentication check has one property: no request reaches protected data or actions unless the server has itself verified valid proof of identity for that request. Each word matters.

  • Server: not the browser, the app, or a header the client chose.
  • Itself verified: not "someone upstream probably did it".
  • For that request: every request, because HTTP has no memory (the previous lesson).
  • Valid proof: a session or token that is genuine, current and issued for this service.

Bypasses are the many ways one of those words fails.

The usual shapes

Trusting something the client controls. The server believes a cookie like admin=true, a hidden form field, a header such as X-User: sam, or a flag in browser code. Anything the client sends, the client can change. Identity must come from a server-side session or a verified signed token.

The forgotten door. The main login page is protected, but an older API route, a debug endpoint, a mobile-app endpoint, an export URL or an admin panel was added later and the check was never attached. Protection that is added path by path is missed path by path. The safer design is deny by default: every route requires authentication unless it is explicitly listed as public.

A check that compares the wrong thing. The code verifies that a token is present but not that it is valid, or accepts any signature, or an unexpected signing algorithm, or an expired token, or one meant for a different service.

Weak credential handling. Default passwords left in place (admin/admin on a device), no limit on guesses so a script can try thousands of passwords, and error messages that reveal whether a username exists, which helps guessing.

Weak recovery. The password-reset flow is the second login page, and often the weaker. Guessable or reusable reset tokens, tokens that never expire, a reset link that stays valid after use, security questions with public answers, or a reset link built from a client-supplied host name, all let an attacker become the account owner without ever seeing the real password.

Session mistakes. The session ID does not change at login (so an ID an attacker planted beforehand becomes logged-in), sessions never expire, or logout does not invalidate the session on the server.

Parser disagreements. Two components read the same request differently. A front proxy decides the path is public, while the application behind it, reading the same URL after normalising it, decides it is a protected route and then treats the request as already approved. These are subtle, which is why bypass flaws appear even in mature products.

Step by step: a request is checked at the front door and at a forgotten side route, and only the central deny-by-default gate covers both

A real case

Read the record's own facts. The product is Microsoft SharePoint, a widely used document and collaboration server that organisations often run themselves. The flaw is "improper authentication", the exact category of this lesson, and the record's CVSS vector (PR:N, UI:N) says no account and no victim action were needed. It appears in CISA's Known Exploited Vulnerabilities catalogue, added on 22 July 2025, and the catalogue notes it as known to be used in ransomware campaigns. That combination is the one to remember: an authentication flaw on a server reachable from outside, requiring nothing from the attacker, is the kind that is exploited quickly after it becomes known. The record does not describe the internal mechanism, and we will not guess at it. What you can take from it is the response pattern: find out where such servers run, apply the vendor's guidance, and, as CISA's action note says, disconnect public-facing versions that no longer receive support.

Notice also the score: 6.5, rated medium. A single spoofing flaw can look modest on paper and still be a serious door-opener when it sits in front of valuable data or can be combined with other flaws. Treat the rating as a starting point, and let the KEV listing (it is being exploited) raise the priority.

Building a check that holds

  1. Centralise it. One piece of middleware or a framework gate that every route passes through, with public routes in a short, reviewed list. Do not rely on each developer remembering.
  2. Deny by default. If the check cannot decide, it denies.
  3. Use proven libraries for sessions, tokens and password hashing. Do not write your own.
  4. Limit guessing. Rate limits, lockouts that slow rather than permanently block, and the same error message for "no such user" and "wrong password".
  5. Make recovery as strong as login. Random single-use reset tokens that expire in minutes, sent only to the address on file.
  6. Rotate the session at login and on privilege change; kill it on logout.
  7. Test the negative. For each protected endpoint, a test that sends no credentials, a bad one and an expired one, and expects a refusal.
  8. Remove what is not used. Old endpoints and default accounts are doors nobody watches. That connects back to attack surface from Level 1.

Vulnerable versus fixed: the client claims who it is and the server believes it, against the server deriving identity from its own session and denying by default

How AI changes this

Attackers. Bypass flaws were found by reading code and probing unusual requests, slow human work. Models that read source code and generate many request variations can look for forgotten doors and proxy disagreements faster and in parallel, and can adapt a known technique to a slightly different product. Anthropic's threat reports show the pattern in broader form; see the September 2026 threat intelligence report for what has been documented. The practical effect is a shorter gap between a flaw becoming known and being used, so patch priority for exposed authentication flaws goes up.

Defenders. The same ability helps review: asking a model to list every route in a codebase and say which lack the central check, or to generate negative tests, is a good use. Treat it as a second reader, not as proof. A model can miss the door that matters.

Agents. Two things are new. Agent platforms add tools and servers that must authenticate callers, and a tool that accepts any caller is a forgotten door with real power behind it. And agents often hold an identity themselves, which has to be proven to the tools it calls. Where a check for an MCP server or an agent tool is missing or weak, the effect is a direct path to what the agent can do. See the MCP security guide for how to review that. The old rule applies unchanged: the server verifies every request itself.

Try it

This lab is two small functions on your own machine. No network involved.

import hmac

USERS = {"sam": "s3cret-lab-only"}      # a fake user store for the lab
SESSIONS = {"abc123": "sam"}            # session ID -> user, as if created at login

# FLAWED: believes whatever the client says about who it is
def whoami_flawed(headers):
    return headers.get("X-User")

# BETTER: identity comes only from a session the server issued
def whoami_checked(headers):
    sid = headers.get("Cookie", "").removeprefix("session=")
    return SESSIONS.get(sid)            # None when not logged in

def admin_page(headers, whoami):
    user = whoami(headers)
    return f"admin data for {user}" if user else "401 denied"

attacks = [{}, {"X-User": "sam"}, {"Cookie": "session=guess"}, {"Cookie": "session=abc123"}]
for a in attacks:
    print(a, "| flawed:", admin_page(a, whoami_flawed), "| checked:", admin_page(a, whoami_checked))

Predict the output before running it. The flawed version lets {"X-User": "sam"} straight in, because the client claimed it. The checked version only admits the real session. Then add a function compare_secrets using hmac.compare_digest and use it for any secret comparison, since it takes the same time whichever character differs.

Check yourself

The login page is secure, but a mobile API route skips the login check. Is the system secure?

No. An attacker uses the unguarded route to reach the same data. Protection has to apply to every path, which is why a central, deny-by-default gate beats adding checks route by route.

Why is the password-reset flow a frequent target?

It is a second way to become the account owner, and it is often built with less care than login. Weak, reusable or non-expiring reset tokens let an attacker take over an account without knowing the password.

CVE-2025-49706 is scored 6.5 (medium) but is listed as exploited in the wild. How should that affect your priority?

Raise it. The score estimates severity in general; the KEV listing shows real attackers are using it now. For a flaw that needs no account and no user action on an internet-facing server, exploitation status matters more than the number.

A token has a valid signature but expired last week. Should the server accept it?

No. A valid signature only proves it was once issued by the server. Expiry, audience and the intended algorithm must all be checked on every request.

Next

Suppose the check works and the server knows exactly who you are. Is everything now allowed? Next: missing authorization, where logged in is not the same as allowed.