SettingsServerAboutFragment renders the server's extended description in a WebView with setJavaScriptEnabled(true):
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url){
Uri uri=Uri.parse(url);
if(uri.getScheme().equals("http") || uri.getScheme().equals("https")){
UiUtils.launchWebBrowser(getActivity(), url);
}else{
Intent intent=new Intent(Intent.ACTION_VIEW, uri);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try{
startActivity(intent);
}catch(ActivityNotFoundException x){
...
}
}
return true;
}
});
The HTML is built from the server's extended_description (see GetInstanceExtendedDescription.Response#content) and rendered with:
webView.loadDataWithBaseURL(null, html, "text/html; charset=utf-8", null, null);
The extended_description field is text the server admin writes, so it is effectively first-party content from the server, but it is content the user did not author. With null as the baseUrl the rendered page has an opaque about:blank origin. Any link or window.open call inside that HTML inherits the same origin and reaches the shouldOverrideUrlLoading handler, which routes non-http schemes (intent:, market:, mailto:, sms:, etc.) to Intent.ACTION_VIEW without an explicit allow-list.
The closest CWE mapping is CWE-79 on the bridge-less surface: a server admin who wants to be hostile can ship HTML that triggers external intents without the user seeing any URL bar.
Suggested fix
Pass the account's instance domain as an https baseUrl:
final String baseUrl="https://"+AccountSessionManager.get(accountID).domain+"/";
webView.loadDataWithBaseURL(baseUrl, html, "text/html; charset=utf-8", null, null);
This gives the rendered page a deterministic origin tied to the server that produced the HTML. The description renders the same way it did before. A subsequent change can add an explicit scheme allow-list inside shouldOverrideUrlLoading, but the baseUrl swap alone is the minimum step from C01 of the WebView posture notes.
A PR is open at #1094.
SettingsServerAboutFragmentrenders the server's extended description in a WebView withsetJavaScriptEnabled(true):The HTML is built from the server's
extended_description(seeGetInstanceExtendedDescription.Response#content) and rendered with:The
extended_descriptionfield is text the server admin writes, so it is effectively first-party content from the server, but it is content the user did not author. Withnullas the baseUrl the rendered page has an opaqueabout:blankorigin. Any link orwindow.opencall inside that HTML inherits the same origin and reaches theshouldOverrideUrlLoadinghandler, which routes non-http schemes (intent:,market:,mailto:,sms:, etc.) toIntent.ACTION_VIEWwithout an explicit allow-list.The closest CWE mapping is CWE-79 on the bridge-less surface: a server admin who wants to be hostile can ship HTML that triggers external intents without the user seeing any URL bar.
Suggested fix
Pass the account's instance domain as an https baseUrl:
This gives the rendered page a deterministic origin tied to the server that produced the HTML. The description renders the same way it did before. A subsequent change can add an explicit scheme allow-list inside
shouldOverrideUrlLoading, but the baseUrl swap alone is the minimum step from C01 of the WebView posture notes.A PR is open at #1094.