> Common URLs are for example `http://xxx`, `https://xxx`, `mailto:xxx` so I
> could just whitelist those 3 types of URLs.

That's exactly what you should do. On the web there are only a few plausible protocols for external links. Whitelist `http:`, `https:`, `mailto:` and optionally include `ftp:` for the less common case someone submits an FTP link. Including more protocols is unnecessary if you don't have a special (uncommon) use case in mind. That said some systems are more permissive than others. The [Wordpress docs][1] define this list of safe protocols in their `wp_allowed_protocols()` function:

> Array of allowed protocols. Defaults to an array containing 'http',
> 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp',
> 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', and
> 'webcal'.

(Most of the additional entries are due to historical reasons.)




> At the same time I'm worried, are there are potentially bad URLs? 

There are pseudo-protocols that have side effects. `javascript:` URLs should definitely not be possible. The `file:` scheme is dangerous as well because local files are often more privileged than web content. For Firefox you especially don't want to allow `chrome:` and `resource:` URIs.

This is an excellent example for a problem where only whitelisting works since it's not possible to keep track of all the custom URI schemes and their effects for every possible browser.


  [1]: https://developer.wordpress.org/reference/functions/wp_allowed_protocols/