Hi, my name is Ian and I'm an aspiring penetration tester. Like many new to security, I started with labs such as WebGoat and DVWA. They are great for learning the basics, but I wanted something closer to real world applications.

So, I've been building my own vulnerable labs that behave more like production systems. This allows me to get hands-on experience finding bugs through logic, data flow, and manual testing rather than relying solely on automated tools.

Recently, I had the chance to test a real application for a local startup, with their permission and confidentiality as top priorities.

Reconnaissance

I was only given a username and password for the client-facing web app, plus a separate set for the admin panel. No other details were provided.

Before testing, I always walk through the application to see what I can and cannot do. This helps me create a mental map of how it functions and makes it easier to spot potential attack points or features that appear or disappear, which is often a sign of a bug or exploit.

Sessions

Whenever an application has login functionality, I start by inspecting sessions and cookies using the browser developer tools. This quickly shows whether flags like HTTPOnly and Secure are set. If not, cookies could be accessed via JavaScript or sent over HTTP.

In this application, session and user data were stored in localStorage in plain text. Values like connectionStatus and signedIn were fully exposed and readable.

None

Attempt to crack the token

Before trying to bypass the login, I attempted to crack the JWT token. The session data confirmed that the application used JWTs. Many applications rely on weak signing keys that can be cracked with tools like Hashcat and wordlists such as rockyou.

In this case, the signing key was not in the SecLists wordlists, so cracking it wasn't possible. I needed to focus on other ways to bypass the login.

Bypass Login

Next, I tested whether changing these values could bypass the login. I logged in, observed how the values updated, then modified signedIn to true and connectionStatus to connected.

{
  "state": {
    "session": {
      "signedIn": true
    },
    "accountData": {
      "id": "XXXXXX",
      "tenant_id": "XXXXX",
      "name": "Reception",
      "description": "Lorem Ipsum.",
      "account_id": "xxxx",
      "isAdmin": true
    },
    "connectionStatus": "connected"
  },
  "version": 0
}

This did not bypass the login, but it sparked another idea. After logging out, the values reset to closed and false. I wondered what would happen if I copied the JWT token and session data, then refreshed the page.

I logged back in, copied the session keys and values from localStorage, and then logged out.

sessionUser: {
      "state":{"session":{"signedIn":true},
       "accountData":{
        "id":"xxxx",
        "tenant_id":"xxxx",
        "name":"Reception",
        "description":"Lorem Ipsum.",
        "account_id":"xxxxx",
        "isAdmin":true},
      "connectionStatus":"connected"},
      "version":0}

xxxxx-manager-access-token TOKEN_HERE
xxxxx-manager-refresh-token REFRESH_TOKEN

If this worked, it would suggest that the session was either not being properly destroyed on logout, or that the backend was not correctly validating active sessions.

For confidentiality, I have removed the tokens and any identifying values.

The xxxxx-manager-access-token entry represents a valid JWT token. This is the token that will be used alongside the sessionUser data when attempting to recreate the localStorage session and test the bypass.

I wanted to make sure the browser had not cached anything, so I opened a new private browsing window for the next step. From there, I navigated back to the website, opened the developer tools, and carefully recreated the localStorage session entries by hand.

I was ready to test, the only thing left to do was to refresh the page…

None

To my surprise, I was immediately logged back into an active session with full account control. This is a critical bug that clearly needs to be addressed as soon as possible.

After digging a bit further and not finding anything else on the client side application, I moved on to testing the admin application.

Admin Application

I carried out the same session review on the admin application and found that it was also using JWT based sessions stored in localStorage in plain text.

Since I was able to bypass the client side application, I repeated the same steps using the admin JWT token and session data to see if the login could be bypassed there as well.

Unfortunately for me, but fortunately for the developers, this approach did not work on the admin side, as active sessions were being properly validated.

However, I noticed that the sessionUser value now includes a new parameter called role. This immediately caught my attention.

{
   "state":{
      "session":{
         "signedIn":true
      },
      "user":{
         "id":"xxxx",
         "email":"xxx@example.com",
         "role":"SUPERADMIN",
         "is_active":true,
         "name":"Joe",
         "surname":"Smith"
      },
      "tenantId":"xxxxx"
   },
   "version":0
}

Privilege Escalation

In the example above, my role is set to SUPERADMIN. I wondered what would happen if I changed this to a more common role, like ADMIN. Would I still be able to access the pages that were available to me as SUPERADMIN?

None

I was then presented with an access denied message. This indicated that while the application does have permission logic in place, it is not verifying that the user is actually assigned to the role defined in the session. Instead, the application is blindly trusting the session data.

This is a critical security vulnerability that should be addressed as soon as possible.

Conclusion

This project was an incredible learning experience. I'm very grateful to the startup for allowing me to practice on a real web application and for trusting me to handle their data responsibly.

Not only did it give me hands-on experience identifying and understanding critical security issues, but it also allowed me to help the team prevent potential attacks in the future. Overall, it was a valuable chance to grow my skills and gain insight into how real-world applications handle security.