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 XML stock API evaluates storeId as SQL while its filter examines a different representation: storeId=1+2 is evaluated; raw UNION is blocked as Attack detected, but Hackvertor XML hex entities decode before the database and allow UNION SELECT username||’:’||password FROM users –. Entity decoding restores the blocked UNION after inspection.

Lab objective/setup

Exercise SQL injection with filter bypass via XML encoding through the endpoint and input recorded in the lab note. storeId=1+2 is evaluated; raw UNION is blocked as Attack detected, but Hackvertor XML hex entities decode before the database and allow UNION SELECT username||':'||password FROM users --.

What I observed

storeId=1+2 is evaluated; raw UNION is blocked as Attack detected, but Hackvertor XML hex entities decode before the database and allow UNION SELECT username||':'||password FROM users --.

The stock-check XML request evaluates arithmetic in storeId, demonstrating that the element reaches a SQL expression context.
The stock-check XML request evaluates arithmetic in storeId, demonstrating that the element reaches a SQL expression context.
A raw UNION SELECT in storeId is rejected with Attack detected before the XML-encoding bypass is applied.
A raw UNION SELECT in storeId is rejected with Attack detected before the XML-encoding bypass is applied.
Hackvertor converts the inert SQL string `UNION SELECT username||':'||password FROM users --` into XML hexadecimal entities.
Hackvertor converts the inert SQL string `UNION SELECT username||':'||password FROM users --` into XML hexadecimal entities.

Why it is vulnerable

storeId=1+2 is evaluated; raw UNION is blocked as Attack detected, but Hackvertor XML hex entities decode before the database and allow UNION SELECT username||':'||password FROM users --. 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

Prove expression evaluation with storeId=1+2, observe that a raw UNION triggers Attack detected, then encode the UNION payload as XML hex entities before submitting it in the stock body. Read the concatenated user credentials from the decoded query result.

The raw storeId UNION request is blocked by the application filter and returns the visible Attack detected response.
The raw storeId UNION request is blocked by the application filter and returns the visible Attack detected response.
Hackvertor encodes the username-and-password UNION query as XML character entities for the storeId element.
Hackvertor encodes the username-and-password UNION query as XML character entities for the storeId element.
Repeater sends the entity-encoded query in storeId so XML decoding reconstructs the SQL after filter inspection.
Repeater sends the entity-encoded query in storeId so XML decoding reconstructs the SQL after filter inspection.
The stock response displays concatenated users credentials, including the administrator value used to complete the lab.
The stock response displays concatenated users credentials, including the administrator value used to complete the lab.

Verification

The lab is confirmed when storeId=1+2 is evaluated; raw UNION is blocked as Attack detected, but Hackvertor XML hex entities decode before the database and allow UNION SELECT username||':'||password FROM users --. The captured result and the Academy solved state provide the verification; an ordinary status code alone does not.

Impact and defensive lesson

Canonicalization gaps let encoded SQL pass a signature filter. Parse and normalize once, validate the normalized value, and still use a parameterized query; a WAF must not be the data layer’s only defense.

References