The WordPress Function sanitize_text_field() Function Doesn’t Sanitize User Input for SQL Statements
As we warned our customers about last week, a recent update to a WordPress plugin that extends WooCommerce, with 300,000+ installs, tried to fix a SQL injection vulnerability. The developer failed to accomplish that, in part because they were using the WordPress function sanitize_text_field() in an apparent attempt to sanitize user input to be used in a SQL statement. That doesn’t work.
The developer was using a prepared SQL statement, which would address this, if used properly, but it wasn’t used properly. Here is the statement:
$results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_name WHERE `id` LIKE '$search' OR `order_id` LIKE '$search' ORDER BY $orderby $order LIMIT %d OFFSET %d", $this->per_page, $offset ) ); |
Relevant to this discussion is the variable $search, which is used directly in the statement. That variable is generated from earlier lines of code:
$request = stripslashes_deep( $_GET ); $results = array(); $paged = $this->get_paged( $request ); $offset = $this->per_page * ( $paged - 1 ); $search = $this->get_search( $request ); |
That code in turn called this function, which passes the user input from the previous code through sanitize_text_field():
public function get_search( $request ) { return ! empty( $request['s'] ) ? sanitize_text_field( $request['s'] ) : false; |
That function doesn’t remove things that would allow SQL injection to occur.
The solution is to replace the $search variables with the appropriate placeholders, in this case %d, and pass the $search variables as arguments after that:
$results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_name WHERE `id` LIKE %d OR `order_id` LIKE %d ORDER BY $orderby $order LIMIT %d OFFSET %d", $search, $search, $this->per_page, $offset ) ); |