Some time ago we were testing an application and we found very limited reflected XSS vuln injecting straight into the page and we had only 22 chars to exploit that.
After some testing, the following payload worked very well:
<svg/onload=alert(1)> or <svg onload=alert(1)>
This <svg> payload has 21 chars, but we still not happy with the size.
Checking the HTML doc it was possible to find the function oncut, obviously, it has fewer chars than onload.
Well, as the function name oncut is quite clear, we need something to cut on the web page.
So, a small HTML tag that accepts text is <p>.
In this case, the payload will be the following:
<p/oncut=alert(1)>A or <p oncut=alert(1)>A
Bingo! We have a functional XSS payload with 19 chars. \o/
The problem: To trigger the payload, of course, the user must try to cut the "A". In other words, different from onload that is automatic, this payload must have user interaction.
Another super short we can use with 18 chars is:
<a/oncut=alert(1)> or <a oncut=alert(1)>
In this case, some text must preexist on page body after injecting the tag <a> and as same from the previous payload, the user must try to cut any text after <a> tag. In other words, also same as the previous example, this payload must have user interaction.