SECURITY: apisandbox: Fix reflected XSS when invalid 'format' is provided

CVE-2025-6594

* Fix validation of API parameters. Follow-up to
  c36b4634e8.
* Add an extra check for parameters that should be required by the UI.
* Remove a fallback code branch that tried to display responses for
  non-pretty formats, which would have been unreachable were it not
  for the format validation bug, and which handled HTML unsafely.

Bug: T395063
Change-Id: I392810e3474ffdbe273b1c668ffce4c8dace1380
This commit is contained in:
Bartosz Dziewoński 2025-06-04 20:39:20 +02:00 committed by Reedy
parent 8a9ef65437
commit 35edc6c2b1

View file

@ -915,7 +915,7 @@
if ( checkPage.tokenWidget ) {
tokenWidgets.push( checkPage.tokenWidget );
}
deferreds.push( checkPage.apiCheckValid() );
deferreds.push( ...checkPage.apiCheckValid() );
checkPage.getQueryParams( params, displayParams, ajaxOptions );
if ( checkPage.paramInfo.mustbeposted !== undefined ) {
method = 'post';
@ -989,6 +989,19 @@
return;
}
if ( params.format === undefined ) {
// While not required by the API, the sandbox UI makes the 'format' parameter required.
// If we reach this point without any value for it, that's a bug, so stop here
// (it would result in incorrect formatting on the results panel).
throw new Error( "'format' parameter is required" );
}
if ( params.action === undefined ) {
// While not required by the API, the sandbox UI makes the 'action' parameter required.
// If we reach this point without any value for it, that's a bug, so stop here
// (it would result in dumping the entire HTML help output on the results panel).
throw new Error( "'action' parameter is required" );
}
const query = $.param( displayParams );
const formatItems = Util.formatRequest( displayParams, params, method, ajaxOptions );
@ -1124,7 +1137,7 @@
.append( Util.parseMsg( 'apisandbox-results-login-suppressed' ) )
.appendTo( $result );
}
let loadTime, match;
let loadTime;
if ( /^text\/mediawiki-api-prettyprint-wrapped(?:;|$)/.test( ct ) ) {
try {
data = JSON.parse( data );
@ -1143,11 +1156,6 @@
}
$result.append( Util.parseHTML( data.html ) );
loadTime = data.time;
} else if ( ( match = data.match( /<pre[ >][\s\S]*<\/pre>/ ) ) ) {
$result.append( Util.parseHTML( match[ 0 ] ) );
if ( ( match = data.match( /"wgBackendResponseTime":\s*(\d+)/ ) ) ) {
loadTime = parseInt( match[ 1 ], 10 );
}
} else {
$( '<pre>' )
.addClass( 'api-pretty-content' )