I’d hooked to ‘wp_insert_post_empty_content’ filter. See https://core.trac.wordpress.org/browser/tags/3.8.1/src/wp-includes/post.php#L2748
//hook at the very end of all filters to prevent other filters from overwriting your return value ( 99 should be high enaugh )
add_filter( 'wp_insert_post_empty_content', 'my_cancel_post_save_function', 99, 2 );
function my_cancel_post_save_function( $maybe_empty, $postarr ) {
if ( true === wp_is_post_revision( $postarr[ 'ID' ] ) ) { //postarr is not an object, but array
return $maybe_empty; //do not forget to return original value to keep other filters working
}
if( true === preg_match("/bad string/", $postarr[ 'post_content' ] ) ) {
return true; // triggers the post saving cancelation in wp_insert_post function
}
return $maybe_empty; //do not forget to return original value to keep other filters working
}