diff --git src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
index e5d6237..bf9e59a 100644
--- src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
+++ src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
@@ -459,6 +459,10 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
 			return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to create new posts.' ), array( 'status' => rest_authorization_required_code() ) );
 		}
 
+		if ( ! $this->current_user_can_assign_terms( $request ) ) {
+			return new WP_Error( 'rest_cannot_assign_term', __( 'You are not allowed to assign this term as this user.' ), array( 'status' => rest_authorization_required_code() ) );
+		}
+
 		return true;
 	}
 
@@ -592,6 +596,10 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
 			return new WP_Error( 'rest_cannot_assign_sticky', __( 'You do not have permission to make posts sticky.' ), array( 'status' => rest_authorization_required_code() ) );
 		}
 
+		if ( ! $this->current_user_can_assign_terms( $request ) ) {
+			return new WP_Error( 'rest_cannot_assign_term', __( 'You are not allowed to assign this term as this user.' ), array( 'status' => rest_authorization_required_code() ) );
+		}
+
 		return true;
 	}
 
@@ -1205,6 +1213,38 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
 	}
 
 	/**
+	 * Checks whether current user can assign all terms sent with the current request.
+	 *
+	 * @since 4.7.0
+	 *
+	 * @param WP_REST_Request $request The request object with post and terms data.
+	 * @return bool
+	 */
+	protected function current_user_can_assign_terms( WP_REST_Request $request ) {
+		$taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) );
+		foreach ( $taxonomies as $taxonomy ) {
+			$base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
+
+			if ( ! isset( $request[ $base ] ) ) {
+				continue;
+			}
+
+			foreach ( $request[ $base ] as $term_id ) {
+				// Invalid terms will be rejected later.
+				if ( ! get_term( $term_id, $taxonomy->name ) ) {
+					continue;
+				}
+
+				if ( ! current_user_can( 'assign_term', (int) $term_id ) ) {
+					return false;
+				}
+			}
+		}
+
+		return true;
+	}
+
+	/**
 	 * Checks if a given post type can be viewed or managed.
 	 *
 	 * @since 4.7.0
diff --git tests/phpunit/tests/rest-api/rest-posts-controller.php tests/phpunit/tests/rest-api/rest-posts-controller.php
index 73864e9..ec7812c 100644
--- tests/phpunit/tests/rest-api/rest-posts-controller.php
+++ tests/phpunit/tests/rest-api/rest-posts-controller.php
@@ -16,6 +16,8 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te
 	protected static $author_id;
 	protected static $contributor_id;
 
+	protected $forbidden_cat;
+
 	public static function wpSetUpBeforeClass( $factory ) {
 		self::$post_id = $factory->post->create();
 
@@ -1342,6 +1344,35 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te
 		$this->assertEquals( array(), $data['categories'] );
 	}
 
+	/**
+	 * @ticket 38505
+	 */
+	public function test_create_post_with_categories_that_cannot_be_assigned_by_current_user() {
+		$cats = self::factory()->category->create_many( 2 );
+		$this->forbidden_cat = $cats[1];
+
+		wp_set_current_user( self::$editor_id );
+		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
+		$params = $this->set_post_data( array(
+			'password'   => 'testing',
+			'categories' => $cats,
+		) );
+		$request->set_body_params( $params );
+
+		add_filter( 'map_meta_cap', array( $this, 'revoke_assign_term' ), 10, 4 );
+		$response = $this->server->dispatch( $request );
+		remove_filter( 'map_meta_cap', array( $this, 'revoke_assign_term' ), 10, 4 );
+
+		$this->assertErrorResponse( 'rest_cannot_assign_term', $response, 403 );
+	}
+
+	public function revoke_assign_term( $caps, $cap, $user_id, $args ) {
+		if ( 'assign_term' === $cap && isset( $args[0] ) && $this->forbidden_cat == $args[0] ) {
+			$caps = array( 'do_not_allow' );
+		}
+		return $caps;
+	}
+
 	public function test_update_item() {
 		wp_set_current_user( self::$editor_id );
 
@@ -1770,6 +1801,28 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te
 		$this->assertEquals( array(), $new_data['categories'] );
 	}
 
+	/**
+	 * @ticket 38505
+	 */
+	public function test_update_post_with_categories_that_cannot_be_assigned_by_current_user() {
+		$cats = self::factory()->category->create_many( 2 );
+		$this->forbidden_cat = $cats[1];
+
+		wp_set_current_user( self::$editor_id );
+		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
+		$params = $this->set_post_data( array(
+			'password'   => 'testing',
+			'categories' => $cats,
+		) );
+		$request->set_body_params( $params );
+
+		add_filter( 'map_meta_cap', array( $this, 'revoke_assign_term' ), 10, 4 );
+		$response = $this->server->dispatch( $request );
+		remove_filter( 'map_meta_cap', array( $this, 'revoke_assign_term' ), 10, 4 );
+
+		$this->assertErrorResponse( 'rest_cannot_assign_term', $response, 403 );
+	}
+
 	public function test_delete_item() {
 		$post_id = $this->factory->post->create( array( 'post_title' => 'Deleted post' ) );
 		wp_set_current_user( self::$editor_id );
