OOUI's 'href' validation still lets through unsafe URLs.
These fail with exceptions, as they should:
new OOUI\ButtonWidget( array( 'href' => "javascript:alert()", 'label' => 'Normal' ) ), new OO.ui.ButtonWidget( { href: 'javascript:alert()', label: 'Normal' } ),
But these pass, and result in buttons that execute JavaScript when clicked: (adapted from https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Embedded_newline_to_break_up_XSS)
new OOUI\ButtonWidget( array( 'href' => "java\nscript:alert()", 'label' => 'Normal' ) ), new OO.ui.ButtonWidget( { href: 'java\nscript:alert()', label: 'Normal' } ),
Both the PHP and the JavaScript code incorrectly treat this as a relative link (they don't recognize that it has a protocol at all). Browsers happily ignore the \n and execute the script upon clicking.
Unless we have some battle-tested URI parsing library handy, I think we should give up on relative URLs and reject everything that doesn't start with a) a whitelisted protocol b) a slash.