Custom Post Type without an archive page

Is this a WordPress feature?

Yes, and the redirect is being done by redirect_canonical(), but the URL is determined by redirect_guess_404_permalink():

redirect_guess_404_permalink()

Attempts to guess the correct URL for a 404 request based on query
vars.

So what’s happening in your case is, WordPress attempts to find a post having book in the slug (post_name), and then if found, WordPress loads that post instead of showing a 404 error page.

How can I disable/change this?

  1. Completely disable redirect_canonical() (which WordPress core hooks on template_redirect) if the current URL path is exactly book as in example.com/book/ and example.com/book?foo=bar.

    So for example, you can use the parse_request hook to disable the canonical redirect:

    add_action( 'parse_request', 'wpse_392546' );
    function wpse_392546( $wp ) {
        if ( 'book' === $wp->request ) {
            remove_action( 'template_redirect', 'redirect_canonical' );
        }
    }
    
  2. Or you can use do_redirect_guess_404_permalink to disable just the attempt of guessing the correct URL as mentioned above.

    So you could use the same hook and function as used in option 1 above, but replace the remove_action() line with:

    add_filter( 'do_redirect_guess_404_permalink', '__return_false' );