Hey guys, so today I was solving an XSS lab and I got stuck for way longer than I expected But I learned something really important, so I'm writing this down before I forget.

Step 1: Understanding the code

I checked the page source and found this JavaScript:

function tracking(search){
    search = search.split('(')[0];
    document.getElementById('tracker').innerHTML = search;
}

So what this does is:

  • It takes input from the search parameter
  • Removes everything after the first ( character
  • Then injects the result into the page using innerHTML

That immediately tells me: User input is going into innerHTML → possible XSS

Step 2: Initial payloads (failed)

I started with a basic payload:

<img src=x onerror=alert(1)>

But the filter removed everything after (, so it became:

<img src=x onerror=alert

So yeah… blocked.

Then I tried removing parentheses:

<img src=x onerror=alert'1'>

Didn't work. Later I realized why: alert'1' is not valid JavaScript syntax

Step 3: Trying backticks

Then I remembered JavaScript backticks:

<img src=x onerror=alert`1`>

Still didn't work.

After some research, I found that HTML attributes sometimes require quotes when using special characters. So I tried:

<img src=x onerror="alert`1`">

This worked — I got an alert.

But the lab was still not solved.

Step 4: Understanding the requirement

I re-read the lab carefully.

It wasn't enough to trigger alert(1) The goal was to access document.cookie

That's where the problem came in:

  • Backticks work for simple calls
  • But for something like alert(document.cookie) → you need parentheses

And parentheses were blocked.

Step 5: The breakthrough payload

After searching for a while, I found this payload:

<img src=x onerror=alert&#0000000040;document.cookie&#0000000041;>

And it worked. Lab solved

None
None

But I didn't want to just copy it — I needed to understand it.

Step 6: Why this works

The filter only removes the actual ( character.

But in this payload:

  • &#0000000040; represents (
  • &#0000000041; represents )

So:

  • The filter sees no ( → allows the payload
  • The browser decodes it later into real parentheses

So the final executed code becomes:

alert(document.cookie)

That's the key idea:

Filters run before HTML entity decoding

Step 7: About zero-padding

You might notice:

&#0000000040;

Instead of:

&#40;

Both are exactly the same.

The extra zeros don't change anything — they might be used to:

  • Bypass weak filters
  • Or just make payloads less obvious

Step 8: Key takeaways

What I learned from this lab:

  1. Blocking characters is not enough — encoding can bypass filters
  2. HTML entities are powerful for bypassing restrictions
  3. Backticks have limitations in real XSS scenarios
  4. Always understand the lab goal, not just trigger an alert

Final Payload

<img src=x onerror=alert&#0000000040;document.cookie&#0000000041;>

That's it. If you're stuck on this lab, don't just try random payloads — understand how the filter works. That's where the real learning is.

Alright, that's all for today

see you in the next story