CVE-2024-1995 (PHP, published 2024-03-20T02:15Z)
Description: value: The Smart Custom Fields plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the relational_posts_search() function in all versions up to, and including, 4.2.2. This makes it possible for authenticated attackers, with subscrber-level access and above, to retrieve post content that is password protected and/or private.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/inc2734/smart-custom-fields
Files changed:
classes/fields/class.field-related-posts.php
classes/fields/class.field-related-terms.php
Commit message: Security fix


Vulnerable code:
			$post_type = explode( ',', $post_types );
			$args      = array(
				'post_type'      => $post_type,
				'order'          => 'ASC',
				'orderby'        => 'ID',
				'posts_per_page' => -1,
				'post_status'    => 'any',
			);
			$click_count = filter_input( INPUT_POST, 'click_count' );
			if ( $click_count ) {
				$posts_per_page = get_option( 'posts_per_page' );
				$offset         = $click_count * $posts_per_page;
				$args           = array_merge(
					$args,
					array(
						'offset'         => $offset,
						'posts_per_page' => $posts_per_page,
					)
				);
			$s = filter_input( INPUT_POST, 's' );
			if ( $s ) {
				$args = array_merge(
					$args,
					array(
						's' => $s,
					)
			}
			$field_name = sanitize_text_field( filter_input( INPUT_POST, 'field_name' ) );
			/**
			 * This filter will be always applied when it queries posts in related posts field.
			 */
			$args = apply_filters( SCF_Config::PREFIX . 'custom_related_posts_args', $args, $field_name, $post_type );
			/**
			 * This filter will only be applied when getting posts via ajax call, therefore it won't be applied for the first load.
			 */
			$args = apply_filters( SCF_Config::PREFIX . 'custom_related_posts_args_ajax_call', $args, $field_name, $post_type );
			$_posts = get_posts( $args );
		if ( ! $post_type ) {
			$post_type = array( 'post' );
		}
		if ( ! preg_match( '/^\d+$/', $limit ) ) {
			$limit = '';
		}
		$args = array(
			'post_type'      => $post_type,
			'order'          => 'ASC',
			'orderby'        => 'ID',
			'posts_per_page' => $posts_per_page,
			'post_status'    => 'any',
		);
		/**
		 * This filter will be always applied when it queries posts in related posts field.
		 */
		$args = apply_filters( SCF_Config::PREFIX . 'custom_related_posts_args', $args, $name, $post_type );
		/**
		 * This filter will only be applied in the first load, therefore it won't be applied when getting posts via ajax call.
		 */
		$args = apply_filters( SCF_Config::PREFIX . 'custom_related_posts_args_first_load', $args, $name, $post_type );

		// Get posts to show in the first load.
		$choices_posts = get_posts( $args );
		$args   = array();
			$taxonomies = explode( ',', $taxonomies );
			$args       = array(
				'taxonomy'     => $taxonomies,
				'order'        => 'ASC',
				'orderby'      => 'ID',
				'number'       => '',
				'hide_empty'   => false,
				'hierarchical' => false,
			);
			$click_count = filter_input( INPUT_POST, 'click_count' );
			if ( $click_count ) {
				$number = get_option( 'posts_per_page' );
				$offset = $click_count * $number;
				$args   = array_merge(
					$args,
					array(
						'offset' => $offset,
						'number' => $number,
					)
				);
			$search = filter_input( INPUT_POST, 'search' );
			if ( $search ) {
				$args = array_merge(
					$args,
					array(
						'search' => $search,
					)
			}
			$_terms = get_terms( $args );
		if ( ! $taxonomies ) {
			$taxonomies = array( 'category' );
		}
		if ( ! preg_match( '/^\d+$/', $limit ) ) {
			$limit = '';
		$number = get_option( 'posts_per_page' );
		// choicse
		$choices_terms = get_terms(
			array(
				'taxonomy'     => $taxonomies,
				'order'        => 'ASC',
				'orderby'      => 'ID',
				'hide_empty'   => false,
				'hierarchical' => false,
				'number'       => $number,
			)
		);
		$choices_li    = array();

Fixed code:

			$post_type              = explode( ',', $post_types );
			$retrievable_post_types = array();
			foreach ( $post_type as $_post_type ) {
				$post_type_object = get_post_type_object( $_post_type );

				if ( current_user_can( $post_type_object->cap->edit_posts ) ) {
					$retrievable_post_types[] = $_post_type;
				}
			if ( $retrievable_post_types ) {
				$args = array(
					'post_type'      => $retrievable_post_types,
					'order'          => 'ASC',
					'orderby'        => 'ID',
					'posts_per_page' => -1,
					'post_status'    => 'any',
				$click_count = filter_input( INPUT_POST, 'click_count' );
				if ( $click_count ) {
					$posts_per_page = get_option( 'posts_per_page' );
					$offset         = $click_count * $posts_per_page;
					$args           = array_merge(
						$args,
						array(
							'offset'         => $offset,
							'posts_per_page' => $posts_per_page,
						)
					);
				}

				$s = filter_input( INPUT_POST, 's' );
				if ( $s ) {
					$args = array_merge(
						$args,
						array(
							's' => $s,
						)
					);
				}

				$field_name = sanitize_text_field( filter_input( INPUT_POST, 'field_name' ) );
				/**
				* This filter will be always applied when it queries posts in related posts field.
				*/
				$args = apply_filters( SCF_Config::PREFIX . 'custom_related_posts_args', $args, $field_name, $post_type );
				/**
				* This filter will only be applied when getting posts via ajax call, therefore it won't be applied for the first load.
				*/
				$args = apply_filters( SCF_Config::PREFIX . 'custom_related_posts_args_ajax_call', $args, $field_name, $post_type );
				$_posts = get_posts( $args );
			}


		$choices_posts  = array();
		if ( $post_type ) {
			$retrievable_post_types = array();

			foreach ( $post_type as $_post_type ) {
				$post_type_object = get_post_type_object( $_post_type );
				if ( current_user_can( $post_type_object->cap->edit_posts ) ) {
					$retrievable_post_types[] = $_post_type;
				}
			}

			if ( $retrievable_post_types ) {
				if ( ! preg_match( '/^\d+$/', $limit ) ) {
					$limit = '';
				}

				$args = array(
					'post_type'      => $retrievable_post_types,
					'order'          => 'ASC',
					'orderby'        => 'ID',
					'posts_per_page' => $posts_per_page,
					'post_status'    => 'any',
				);

				/**
				* This filter will be always applied when it queries posts in related posts field.
				*/
				$args = apply_filters( SCF_Config::PREFIX . 'custom_related_posts_args', $args, $name, $post_type );

				/**
				* This filter will only be applied in the first load, therefore it won't be applied when getting posts via ajax call.
				*/
				$args = apply_filters( SCF_Config::PREFIX . 'custom_related_posts_args_first_load', $args, $name, $post_type );

				// Get posts to show in the first load.
				$choices_posts = get_posts( $args );
			}
		}

			$taxonomies             = explode( ',', $taxonomies );
			$retrievable_taxonomies = array();
			foreach ( $taxonomies as $_taxonomy ) {
				$tax = get_taxonomy( $_taxonomy );

				if ( current_user_can( $tax->cap->manage_terms ) ) {
					$retrievable_taxonomies[] = $_taxonomy;
				}
			if ( $retrievable_taxonomies ) {
				$args = array(
					'taxonomy'     => $retrievable_taxonomies,
					'order'        => 'ASC',
					'orderby'      => 'ID',
					'number'       => '',
					'hide_empty'   => false,
					'hierarchical' => false,
				$click_count = filter_input( INPUT_POST, 'click_count' );
				if ( $click_count ) {
					$number = get_option( 'posts_per_page' );
					$offset = $click_count * $number;
					$args   = array_merge(
						$args,
						array(
							'offset' => $offset,
							'number' => $number,
						)
					);
				}

				$search = filter_input( INPUT_POST, 'search' );
				if ( $search ) {
					$args = array_merge(
						$args,
						array(
							'search' => $search,
						)
					);
				}

				$_terms = get_terms( $args );
			}


		$choices_terms = array();
		$number        = get_option( 'posts_per_page' );

		if ( $taxonomies ) {
			$retrievable_taxonomies = array();

			foreach ( $taxonomies as $_taxonomy ) {
				$tax = get_taxonomy( $_taxonomy );

				if ( current_user_can( $tax->cap->manage_terms ) ) {
					$retrievable_taxonomies[] = $_taxonomy;
				}
			}

			if ( $retrievable_taxonomies ) {
				if ( ! preg_match( '/^\d+$/', $limit ) ) {
					$limit = '';
				}

				// choicse
				$choices_terms = get_terms(
					array(
						'taxonomy'     => $taxonomies,
						'order'        => 'ASC',
						'orderby'      => 'ID',
						'hide_empty'   => false,
						'hierarchical' => false,
						'number'       => $number,
					)
				);
			}
		$choices_li = array();