On eBay, the My World section allows users and businesses to construct a profile, with shipping information, returns policies, and also blocks of arbitrary text specified by the user.
All of the input boxes have a note below saying that you can’t add HTML, so I was interested to see how it checks/prevents you from entering any.

I tried adding in some tags, <a>, <span>, <script>, however they’re all filtered out. In addition to this, you can’t use double quotes (so you can’t break out of attributes). However, it turns out they use a blacklist of HTML tags. I tried a deprecated tag, <plaintext>, and to my surprise it passed through fine.

I don’t like the plaintext tag, as it caused the rest of the page to render horribly (as expected), so I tried a few more. <fn> and <credit> both passed through too.
Now we have a way to inject HTML, I added an onhover event to the injected element. Without the use of quotes, we can use the String.fromCharCode function and eval to load an external script - this is necessary as the character limit on the textbox is 1k.

From this point onwards, it is trivial to weaponise this into a working worm. We get the username from the element #gh_uh, construct a form post to the bio page and add ourselves to the logged in users bio.

There is no CSRF protection on this form, which makes it even easier as we don’t need to scrape a token from anywhere.
In addition to this, all of the cookies are stored under *.ebay.com, and they’re not using HTTPOnly so we can steal this too.
Fix
eBay responded by encoding all HTML entities on output.