Output encoding is context-specific. If you're only putting the output of this function into HTML text elements - not into attributes, not into strings (or anywhere else) in a script, not into CSS, etc. - you might be OK. For now. If you're aiming for any other context, you're definitely not OK. Here are just a few (this isn't a comprehensive list, don't try to make a comprehensive list, you'll most likely fail and even if you don't the next ECMAScript or HTML update will break your magical unicorn of a viable blacklist for you).
- You're not filtering
\
, which can be used to escape the legitimate string-ending '
or "
. If the attacker controls another string on the same line, that string will be interpreted as code.
- You're not filtering `, which is used to delimit template strings in JS; an attacker would be able to break out of one of those trivially.
- You're not filtering
${
or }
, which are used to create expressions for expansion within a template string; the text between them is treated as code.
Just use output encoding of everything non-alphanumeric if you want to be really safe, or at least use a whitelist of non-alphanumeric characters to not encode (and be conservative with it). If you're using the filter only for a specific context or two (say, HTML text and non-event HTML attributes), you can maybe get by with a specific "blacklist" of characters to filter, but it's riskier than going the other way.
<img src=[USERINPUT] alt=[USERINPUT]/>
:<img src=heh.jpg onclick=javascript:alert(document.cookie); alt=[USERINPUT]/>
. Your XSS filter relies on people writing HTML code a certain way.