Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/class-zoninator.php
Original file line number Diff line number Diff line change
Expand Up @@ -1532,8 +1532,13 @@ private function filter_zone_feed_fields( $results ) {
$filtered_results[ $i ] = new stdClass();
}

// phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found -- see https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/598
$filtered_results[ $i ]->$field = $result->$field;
// Don't expose content or excerpt for password-protected posts
if ( ( 'post_content' === $field || 'post_excerpt' === $field ) && ! empty( $result->post_password ) ) {
$filtered_results[ $i ]->$field = '';
} else {
// phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found -- see https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/598
$filtered_results[ $i ]->$field = $result->$field;
}
}

++$i;
Expand Down
45 changes: 45 additions & 0 deletions tests/unit/class-zoninator-api-controller-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -433,4 +433,49 @@ private function add_a_zone( $slug = 'zone-1' ) {
'slug' => $slug,
));
}

/**
* Test that password-protected posts do NOT expose their content in zone feed
* This test verifies the security fix is working
*/
public function test_password_protected_posts_do_not_expose_content_in_zone_feed() {
// Create a password-protected post
$post_id = wp_insert_post(array(
'post_title' => 'Password-protected post',
'post_content' => 'This is secret content that should not be exposed!',
'post_excerpt' => 'This is a secret excerpt that should not be exposed!',
'post_status' => 'publish',
'post_password' => 'secret123',
'post_type' => 'post'
));

$this->assertNotWPError($post_id);

// Create a zone and add the password-protected post to it
$zone_id = $this->create_a_zone('test-security-zone', 'Test Security Zone');
$response = $this->put('/zoninator/v1/zones/' . $zone_id . '/posts', array(
'post_ids' => array($post_id),
));
$this->assertResponseStatus($response, 200);

// Test as unauthenticated user (simulating public access)
wp_set_current_user(0);

// Get the zone posts via REST API
$response = $this->get('/zoninator/v1/zones/' . $zone_id . '/posts');
$this->assertResponseStatus($response, 200);

$data = $response->get_data();
$this->assertIsArray($data);
$this->assertCount(1, $data);

$post_data = $data[0];
$this->assertEquals($post_id, $post_data->ID);
$this->assertEquals('Password-protected post', $post_data->post_title);

// Security fix: password-protected content and excerpt should be empty
$this->assertEquals('', $post_data->post_content);
$this->assertEquals('', $post_data->post_excerpt);
}

}