PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / 5.5.0
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification v5.5.0
5.12.0 5.13.0 5.13.1 5.11.0 5.10.0 5.9.0 5.8.0 5.8.1 5.7.0 5.6.2 5.6.3 5.6.1 5.6.0 5.5.0 5.4.0 5.3.2 5.3.1 5.1.6 5.1.5 trunk 2.1.5 2.11 2.12 2.13 2.15 All 47 releases
← All changes | core/Ajax.class.php +29 -8 3.1.0 → 5.5.0 View file →
@@ -48,8 +48,12 @@
48 48 /**
49 49 * Load and get the template we need.
50 50 */
51 51 public function getTemplate() {
52 + // A nonce proves intent, not authorization — gate on capability too.
53 + if ( ! current_user_can( 'manage_options' ) ) {
54 + wp_die( -1, 403 );
55 + }
52 56 $this->get_logger()->debug( 'getTemplate called', [
53 57 'plugin' => 'double-opt-in',
54 58 'class' => __CLASS__,
55 59 'method' => __METHOD__,
@@ -56,12 +60,19 @@
56 60 'post' => $_POST,
57 61 ] );
58 62
59 63 $content = '';
60 - if ( isset( $_POST['template'] ) && wp_verify_nonce( $_POST['nonce'], 'f12_doi_templateloader' ) ) {
61 - $template_path = plugin_dir_path( dirname( __FILE__ ) ) . 'mails/' . esc_attr( sanitize_text_field( $_POST['template'] ) ) . '.html';
64 + if ( isset( $_POST['template'] ) && wp_verify_nonce( wp_unslash( $_POST['nonce'] ), 'f12_doi_templateloader' ) ) {
65 + // Use sanitize_file_name() to prevent path traversal attacks
66 + $template_name = sanitize_file_name( wp_unslash( $_POST['template'] ) );
67 + $mails_dir = plugin_dir_path( dirname( __FILE__ ) ) . 'mails/';
68 + $template_path = $mails_dir . $template_name . '.html';
62 69
63 - if ( file_exists( $template_path ) ) {
70 + // Verify the resolved path is within the allowed directory (prevent path traversal)
71 + $real_template_path = realpath( $template_path );
72 + $real_mails_dir = realpath( $mails_dir );
73 +
74 + if ( $real_template_path && $real_mails_dir && strpos( $real_template_path, $real_mails_dir ) === 0 && file_exists( $real_template_path ) ) {
64 75 $this->get_logger()->debug( 'Template file found, loading content', [
65 76 'plugin' => 'double-opt-in',
66 77 'class' => __CLASS__,
67 78 'method' => __METHOD__,
@@ -66,9 +77,9 @@
66 77 'class' => __CLASS__,
67 78 'method' => __METHOD__,
68 79 'template_path' => $template_path,
69 80 ] );
70 - $content = file_get_contents( $template_path );
81 + $content = file_get_contents( $real_template_path );
71 82 } else {
72 83 $this->get_logger()->warning( 'Template file not found', [
73 84 'plugin' => 'double-opt-in',
74 85 'class' => __CLASS__,
@@ -93,8 +104,13 @@
93 104 /**
94 105 * Return the Popup for the HASH DOI
95 106 */
96 107 public function getDetails() {
108 + // Exposes opt-in PII (email, IPs, all form fields). A nonce proves
109 + // intent, not authorization — require the capability explicitly.
110 + if ( ! current_user_can( 'manage_options' ) ) {
111 + wp_die( -1, 403 );
112 + }
97 113 $this->get_logger()->debug( 'getDetails called', [
98 114 'plugin' => 'double-opt-in',
99 115 'class' => __CLASS__,
100 116 'method' => __METHOD__,
@@ -100,9 +116,9 @@
100 116 'method' => __METHOD__,
101 117 'post' => $_POST,
102 118 ] );
103 119
104 - if ( isset( $_POST['hash'] ) && wp_verify_nonce( $_POST['nonce'], 'f12_doi_details' ) ) {
120 + if ( isset( $_POST['hash'] ) && wp_verify_nonce( wp_unslash( $_POST['nonce'] ), 'f12_doi_details' ) ) {
105 121 global $wpdb;
106 122 $tableName = $wpdb->prefix . 'f12_cf7_doubleoptin';
107 123 $hash = sanitize_text_field( $_POST['hash'] );
108 124
@@ -147,8 +163,12 @@
147 163 ],
148 164 ] );
149 165
150 166 $formfields = maybe_unserialize( $OptIn->get_content() );
167 + // Handle nested content structure (e.g., Avada stores {data: {...}, field_labels: {...}, ...})
168 + if ( is_array( $formfields ) && isset( $formfields['data'] ) && is_array( $formfields['data'] ) && ! isset( $formfields['fields'] ) ) {
169 + $formfields = $formfields['data'];
170 + }
151 171 ob_start();
152 172 ?>
153 173 <h2><?php echo esc_html( $OptIn->get_hash() ); ?></h2>
154 174 <?php if ( current_user_can( 'manage_options' ) ): ?>
@@ -167,9 +187,9 @@
167 187 <td><?php _e( 'Key', 'double-opt-in' ); ?></td>
168 188 <td><?php _e( 'Value', 'double-opt-in' ); ?></td>
169 189 </tr>
170 190 <tr>
171 - <td><?php _e( 'ID', 'f12-cf7-doupleoptin' ); ?></td>
191 + <td><?php _e( 'ID', 'double-opt-in' ); ?></td>
172 192 <td><?php echo esc_html( $OptIn->get_id() ); ?></td>
173 193 </tr>
174 194 <tr>
175 195 <td><?php _e( 'CF7 Form ID', 'double-opt-in' ); ?></td>
@@ -246,10 +266,11 @@
246 266 'hook' => $hook,
247 267 ] );
248 268
249 269 if ( $hook == 'tools_page_f12doubleoptin' ) {
250 - wp_enqueue_style( 'f12-cf7-doubleoptin-admin', plugins_url( 'assets/admin-style.css', __FILE__ ) );
251 - wp_enqueue_script( 'f12-cf7-doubleoptin-admin', plugins_url( 'assets/f12-cf7-popup.js', __FILE__ ), [ 'jquery' ] );
270 + $ver = defined( 'FORGE12_OPTIN_VERSION' ) ? FORGE12_OPTIN_VERSION : false;
271 + wp_enqueue_style( 'f12-cf7-doubleoptin-admin', plugins_url( 'assets/admin-style.css', __FILE__ ), array(), $ver );
272 + wp_enqueue_script( 'f12-cf7-doubleoptin-admin', plugins_url( 'assets/f12-cf7-popup.js', __FILE__ ), [ 'jquery' ], $ver, true );
252 273
253 274 $this->get_logger()->info( 'Admin styles and scripts enqueued for DOI tools page', [
254 275 'plugin' => 'double-opt-in',
255 276 'class' => __CLASS__,