PluginProbe
wpForo Forum / 3.2.0
wpForo Forum v3.2.0
3.2.0 3.1.7 3.1.6 3.1.5 3.1.4 3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.10 1.4.11 All 140 releases
← All changes | classes/Forms.php +41 -4 3.1.4 → 3.2.0 View file →
@@ -320,9 +320,9 @@
320 320 $html .= esc_html( implode( ', ', $f['value'] ) );
321 321 } else {
322 322 $f = $this->prepare_values( $f, WPF()->current_object['userid'] );
323 323 $html .= '<div class="wpf-field-wrap">';
324 - $html .= $f['value'];
324 + $html .= ( is_scalar( $f['value'] ) && ! $this->is_display_value_safe_html( $f ) ) ? esc_html( (string) $f['value'] ) : $f['value'];
325 325 $html .= '</div>';
326 326 }
327 327 } else {
328 328 if( $default_values = wpforo_preg_grep_recursive( '#^\[.+?]$#isu', $f['values'] ) ) {
@@ -1216,14 +1216,35 @@
1216 1216 $var = trim( (string) $var );
1217 1217 if( ! strlen( (string) $var ) ) return [];
1218 1218 }
1219 1219 if( is_serialized( $var ) ) {
1220 - $var = unserialize( $var );
1220 + // This value can come straight from the request: the field state is
1221 + // rebuilt from POST, and prepare_args() HTML-decodes it first, so an
1222 + // entity-encoded payload arrives here fully restored. Never
1223 + // instantiate classes, and never let one through as a value.
1224 + $decoded = unserialize( $var, [ 'allowed_classes' => false ] );
1225 + if( is_array( $decoded ) ) {
1226 + $var = $decoded;
1227 + } elseif( is_scalar( $decoded ) ) {
1228 + $var = [ $decoded ];
1229 + } else {
1230 + return [];
1231 + }
1221 1232 } elseif( is_scalar( $var ) && strpos( (string) $var, $sep ) !== false ) {
1222 1233 $var = explode( $sep, $var );
1223 1234 }
1224 -
1225 - return array_map( 'trim', (array) $var );
1235 +
1236 + // A multi-choice field value is a flat list of scalars. Only arrays and
1237 + // objects are dropped, which a crafted payload can nest here and which
1238 + // are a TypeError in trim() on PHP 8. Every other type is cast exactly
1239 + // as trim() used to coerce it, so null and bool values are unchanged.
1240 + $values = [];
1241 + foreach( (array) $var as $key => $value ) {
1242 + if( is_array( $value ) || is_object( $value ) ) continue;
1243 + $values[ $key ] = trim( (string) $value );
1244 + }
1245 +
1246 + return $values;
1226 1247 }
1227 1248
1228 1249 public function build_array_using_string_rows( $string, $regexp = '' ) {
1229 1250 if( is_scalar( $string ) ) {
@@ -1294,8 +1315,24 @@
1294 1315
1295 1316 return $value;
1296 1317 }
1297 1318
1319 + /**
1320 + * Whether prepare_values()/esc_field() already turned $f['value'] into trusted,
1321 + * pre-escaped HTML for this field type/name (so it must NOT be esc_html()'d again
1322 + * before being echoed).
1323 + *
1324 + * @param array $f field arguments (after prepare_values()/esc_field())
1325 + *
1326 + * @return bool
1327 + */
1328 + public function is_display_value_safe_html( $f ) {
1329 + $safe_types = [ 'url', 'email', 'tel', 'file', 'avatar', 'color', 'textarea', 'tinymce', 'datetime', 'html' ];
1330 + $safe_names = [ 'skype', 'location', 'signature', 'about' ];
1331 +
1332 + return in_array( wpfval( $f, 'type' ), $safe_types, true ) || in_array( wpfval( $f, 'name' ), $safe_names, true );
1333 + }
1334 +
1298 1335 public function esc_field( $f ) {
1299 1336 if( wpfkey( $f, 'value' ) ) {
1300 1337 $f['value'] = wpforo_trim( $f['value'] );
1301 1338 if( in_array( wpfval( $f, 'type' ), [ 'textarea', 'tinymce' ], true ) ) {