csrf
blastqr_settings_page() is the add_menu_page callback (capability manage_options, slug blastqr-settings). On any request where isset($_POST['submit']), it writes blastqr_id_albergo, blastqr_id_stile, blastqr_dc, blastqr_action_type, blastqr_enable_qr, blastqr_fixed_discount_code, blastqr_type_qr, blastqr_custom_css, and related flags via update_option() with no wp_nonce_field in the <form method="post" action="#"> and no check_admin_referer / wp_verify_nonce / extra current_user_can in the handler. WordPress still capability-gates the page, so a Subscriber cannot POST it directly, but a logged-in administrator who submits a cross-site form to /wp-admin/admin.php?page=blastqr-settings persists the attacker's values. Observable consequence: aggiungi_form_html() (hooked to wp_footer as stampaForm, or registered as a shortcode) consumes those IDs as the public form's action and hidden id_albergo/id_stile/dc fields pointing at https://book.blastness.com/results or https://www.blastnessbooking.com/premium|reservations, so every subsequent reservation and the modify/cancel link is sent to a property the attacker controls. The same POST can set blastqr_enable_qr=1 (show the form to guests) and plant the stored-XSS payloads in the sibling finding. This is POST (SameSite=Lax may block some browsers); it is still a missing nonce on a payment-flow setting.
includes/settings-page.php:4-12,125-143,286
RecommendationAdd wp_nonce_field('blastqr_save_settings') to the settings form and call check_admin_referer('blastqr_save_settings') plus current_user_can('manage_options') before any update_option. Prefer the Settings API (register_setting + settings_fields) so the options.php nonce is automatic. Whitelist action_type to premium|advanced|aibe and type_qr to full-width|box.