| @@ -982,15 +982,15 @@ | ||
| 982 | 982 | case 'datetime': |
| 983 | 983 | $f['value'] = wpforo_date( $f['value'], 'datetime', false ); |
| 984 | 984 | break; |
| 985 | 985 | case 'url': |
| 986 | - $f['value'] = sprintf( '<a href="%1$s" target="_blank" rel="nofollow">%2$s</a>', $f['value'], $f['value'] ); | |
| 986 | + $f['value'] = sprintf( '<a href="%1$s" target="_blank" rel="nofollow">%2$s</a>', esc_url( $f['value'] ), esc_html( $f['value'] ) ); | |
| 987 | 987 | break; |
| 988 | 988 | case 'email': |
| 989 | - $f['value'] = sprintf( '<a href="mailto:%1$s" rel="nofollow">%2$s</a>', $f['value'], $f['value'] ); | |
| 989 | + $f['value'] = sprintf( '<a href="mailto:%1$s" rel="nofollow">%2$s</a>', esc_attr( $f['value'] ), esc_html( $f['value'] ) ); | |
| 990 | 990 | break; |
| 991 | 991 | case 'tel': |
| 992 | - $f['value'] = sprintf( '<a href="tel:%1$s" rel="nofollow">%2$s</a>', $f['value'], $f['value'] ); | |
| 992 | + $f['value'] = sprintf( '<a href="tel:%1$s" rel="nofollow">%2$s</a>', esc_attr( $f['value'] ), esc_html( $f['value'] ) ); | |
| 993 | 993 | break; |
| 994 | 994 | case 'file': |
| 995 | 995 | if( ! empty( $f['value'] ) ) { |
| 996 | 996 | if( is_array( $f['value'] ) ) { |
| @@ -1005,17 +1005,17 @@ | ||
| 1005 | 1005 | $extension = pathinfo( $f['value'], PATHINFO_EXTENSION ); |
| 1006 | 1006 | if( wpforo_is_image( $extension ) ) { |
| 1007 | 1007 | $f['value'] = sprintf( |
| 1008 | 1008 | '<a href="%1$s" target="_blank" title="%2$s"><img src="%1$s" alt="%2$s" class="wpf-field-file-img" style="max-width:120px; max-height:120px"></a>', |
| 1009 | - $file_url, | |
| 1010 | - $file_name | |
| 1009 | + esc_url( $file_url ), | |
| 1010 | + esc_attr( $file_name ) | |
| 1011 | 1011 | ); |
| 1012 | 1012 | } elseif( wpforo_is_audio( $extension ) ) { |
| 1013 | - $f['value'] = sprintf( '<audio src="%1$s" controls title="%2$s"></audio>', $file_url, $file_name ); | |
| 1013 | + $f['value'] = sprintf( '<audio src="%1$s" controls title="%2$s"></audio>', esc_url( $file_url ), esc_attr( $file_name ) ); | |
| 1014 | 1014 | } elseif( wpforo_is_video( $extension ) ) { |
| 1015 | - $f['value'] = sprintf( '<video src="%1$s" controls title="%2$s"></video>', $file_url, $file_name ); | |
| 1015 | + $f['value'] = sprintf( '<video src="%1$s" controls title="%2$s"></video>', esc_url( $file_url ), esc_attr( $file_name ) ); | |
| 1016 | 1016 | } else { |
| 1017 | - $f['value'] = sprintf( '<a href="%s" target="_blank">%s</a>', $file_url, $file_name ); | |
| 1017 | + $f['value'] = sprintf( '<a href="%s" target="_blank">%s</a>', esc_url( $file_url ), esc_html( $file_name ) ); | |
| 1018 | 1018 | } |
| 1019 | 1019 | } |
| 1020 | 1020 | break; |
| 1021 | 1021 | case 'avatar': |
| @@ -1022,18 +1022,18 @@ | ||
| 1022 | 1022 | $f['value'] = ( WPF()->usergroup->can( 'va' ) && wpforo_setting( 'profiles', 'avatars' ) ) ? WPF()->member->get_avatar_html( $f['value'], $userid ) : ''; |
| 1023 | 1023 | break; |
| 1024 | 1024 | case 'color': |
| 1025 | 1025 | if( $f['value'] ) { |
| 1026 | - $f['value'] = '<input type="color" value="' . $f['value'] . '" disabled title="' . $f['value'] . '" style="min-width: 100px; min-height: 25px;">'; | |
| 1026 | + $f['value'] = '<input type="color" value="' . esc_attr( $f['value'] ) . '" disabled title="' . esc_attr( $f['value'] ) . '" style="min-width: 100px; min-height: 25px;">'; | |
| 1027 | 1027 | } |
| 1028 | 1028 | break; |
| 1029 | 1029 | } |
| 1030 | 1030 | switch( $f['name'] ) { |
| 1031 | 1031 | case 'skype': |
| 1032 | - $f['value'] = sprintf( '<a href="skype:%s?userinfo" rel="nofollow">%s</a>', $f['value'], $f['value'] ); | |
| 1032 | + $f['value'] = sprintf( '<a href="skype:%s?userinfo" rel="nofollow">%s</a>', esc_attr( $f['value'] ), esc_html( $f['value'] ) ); | |
| 1033 | 1033 | break; |
| 1034 | 1034 | case 'location': |
| 1035 | - $f['value'] = sprintf( '<a href="//maps.google.com/?q=%s" target="_blank" rel="nofollow">%s</a>', $f['value'], $f['value'] ); | |
| 1035 | + $f['value'] = sprintf( '<a href="//maps.google.com/?q=%s" target="_blank" rel="nofollow">%s</a>', esc_attr( $f['value'] ), esc_html( $f['value'] ) ); | |
| 1036 | 1036 | break; |
| 1037 | 1037 | case 'signature': |
| 1038 | 1038 | $f['value'] = wpforo_signature( $f['value'], [ 'echo' => 0 ] ); |
| 1039 | 1039 | break; |
| @@ -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 ) ) { |