Authorization disclaimer. This walkthrough is limited to the intentionally vulnerable PortSwigger Web Security Academy lab linked below. Test only systems you own or are explicitly authorized to assess.

Overview

The browser assigns attacker input to an HTML-parsing sink: an injected <script> does not execute through innerHTML, but <img src=1 onerror=alert(1)> creates an element and fires its error handler. The contrast between inert script text and the generated image handler shows which element type executes through this sink.

Lab objective/setup

Exercise DOM XSS in innerHTML sink using source location.search through the endpoint and input recorded in the lab note. An injected <script> does not execute through innerHTML, but <img src=1 onerror=alert(1)> creates an element and fires its error handler.

What I observed

an injected <script> does not execute through innerHTML, but <img src=1 onerror=alert(1)> creates an element and fires its error handler.

The search page displays ordinary location.search text in the innerHTML result div before any markup is tested.
The search page displays ordinary location.search text in the innerHTML result div before any markup is tested.
A script element inserted through innerHTML remains inert, establishing that this sink does not execute inserted script tags.
A script element inserted through innerHTML remains inert, establishing that this sink does not execute inserted script tags.

Why it is vulnerable

An injected <script> does not execute through innerHTML, but <img src=1 onerror=alert(1)> creates an element and fires its error handler. The application passes that value into the security-sensitive operation without the context-specific validation or encoding needed to prevent this result.

Walkthrough in the authorized PortSwigger lab

Trace the search value from location.search into innerHTML, test the non-executing script element, then use the image error-handler payload. Confirm that the browser creates an img node and fires onerror when its invalid source fails.

The image payload `<img src=1 onerror=alert(1)>` is supplied through location.search for the innerHTML assignment.
The image payload `<img src=1 onerror=alert(1)>` is supplied through location.search for the innerHTML assignment.
Developer Tools shows the innerHTML sink created an img element with src 1 and an onerror alert handler.
Developer Tools shows the innerHTML sink created an img element with src 1 and an onerror alert handler.
Browser alert dialog showing 1 after the malformed image source triggers onerror on the element created by innerHTML.
Browser alert dialog showing 1 after the malformed image source triggers onerror on the element created by innerHTML.

Verification

The lab is confirmed when an injected <script> does not execute through innerHTML, but <img src=1 onerror=alert(1)> creates an element and fires its error handler. The captured result and the Academy solved state provide the verification; an ordinary status code alone does not.

Impact and defensive lesson

DOM XSS can steal same-origin data or act as the victim. Prefer textContent for search output, sanitize unavoidable HTML with a maintained policy, and deploy CSP as defense in depth rather than as the primary fix.

References