Security hardening and accessibility improvements (v1.1.0)

Address findings from security audit: wrap inline JSON.parse in
try/catch to prevent consent flow failure on corrupted cookies,
allowlist admin tab parameter, clamp consent_expiry server-side,
escape all server values in admin JS table builder, fix focus trap
listener cleanup, add aria-labelledby and banner focus for screen
readers, skip frontend loading during AJAX.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-18 10:32:16 +00:00
parent 0a73181ea7
commit 2294c8eda7
7 changed files with 146 additions and 24 deletions

View File

@@ -102,7 +102,6 @@ class ATT_Consent_Admin {
return;
}
$active_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'general'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$tabs = array(
'general' => __( 'General', 'att-consent' ),
'appearance' => __( 'Appearance', 'att-consent' ),
@@ -110,6 +109,10 @@ class ATT_Consent_Admin {
'scripts' => __( 'Custom Scripts', 'att-consent' ),
'advanced' => __( 'Advanced', 'att-consent' ),
);
$active_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'general'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( ! array_key_exists( $active_tab, $tabs ) ) {
$active_tab = 'general';
}
$settings = ATT_Consent::get_settings();
?>
@@ -163,7 +166,7 @@ class ATT_Consent_Admin {
$settings['gtm_container_id'] = sanitize_text_field( $_POST['gtm_container_id'] ?? '' );
$settings['consent_mode'] = in_array( $_POST['consent_mode'] ?? '', array( 'advanced', 'basic' ), true ) ? $_POST['consent_mode'] : 'advanced';
$settings['banner_position'] = in_array( $_POST['banner_position'] ?? '', array( 'bottom', 'top', 'center' ), true ) ? $_POST['banner_position'] : 'bottom';
$settings['consent_expiry'] = absint( $_POST['consent_expiry'] ?? 365 );
$settings['consent_expiry'] = min( 730, max( 1, absint( $_POST['consent_expiry'] ?? 365 ) ) );
$settings['floating_widget'] = in_array(
$_POST['floating_widget'] ?? '',
array( 'bottom-right', 'right', 'none' ),

View File

@@ -104,7 +104,7 @@ class ATT_Consent {
new ATT_Consent_Admin();
}
if ( ! is_admin() || wp_doing_ajax() ) {
if ( ! is_admin() ) {
require_once ATT_CC_PLUGIN_DIR . 'includes/class-frontend.php';
new ATT_Consent_Frontend();
}

View File

@@ -80,7 +80,9 @@ g('js',new Date());
if(c.ads_data_redaction){g('set','ads_data_redaction',true);}
if(c.url_passthrough){g('set','url_passthrough',true);}
var ck=document.cookie.match(/(?:^|; )att_cc_consent=([^;]*)/);
var st=ck?JSON.parse(decodeURIComponent(ck[1])):null;
var st=null;
if(ck){try{st=JSON.parse(decodeURIComponent(ck[1]));}catch(e){}}
if(st){
g('consent','default',{
ad_storage:st.marketing?'granted':'denied',
@@ -235,10 +237,10 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
esc_attr( $s['btn_preferences_text'] )
);
$banner_html = '<div id="att-cc-banner" class="' . esc_attr( $position_class ) . '" role="dialog" aria-label="' . esc_attr__( 'Cookie consent', 'att-consent' ) . '" aria-hidden="false" style="' . $style_vars . '">
$banner_html = '<div id="att-cc-banner" class="' . esc_attr( $position_class ) . '" role="dialog" aria-labelledby="att-cc-banner-heading" aria-hidden="false" tabindex="-1" style="' . $style_vars . '">
<div class="att-cc-banner__inner">
<div class="att-cc-banner__content">
<h2 class="att-cc-banner__heading">' . esc_html( $s['banner_heading'] ) . '</h2>
<h2 id="att-cc-banner-heading" class="att-cc-banner__heading">' . esc_html( $s['banner_heading'] ) . '</h2>
<p class="att-cc-banner__message">' . wp_kses_post( $s['banner_message'] ) . '</p>
</div>
<div class="att-cc-banner__actions">
@@ -249,10 +251,10 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
</div>
</div>';
$modal_html = '<div id="att-cc-modal" role="dialog" aria-label="' . esc_attr__( 'Cookie preferences', 'att-consent' ) . '" aria-hidden="true" aria-modal="true" style="' . $style_vars . '">
$modal_html = '<div id="att-cc-modal" role="dialog" aria-labelledby="att-cc-modal-heading" aria-hidden="true" aria-modal="true" style="' . $style_vars . '">
<div class="att-cc-modal__overlay"></div>
<div class="att-cc-modal__dialog">
<h2 class="att-cc-modal__heading">' . esc_html__( 'Manage Cookie Preferences', 'att-consent' ) . '</h2>
<h2 id="att-cc-modal-heading" class="att-cc-modal__heading">' . esc_html__( 'Manage Cookie Preferences', 'att-consent' ) . '</h2>
<div class="att-cc-modal__category">
<div class="att-cc-modal__cat-header">