[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f1EDCf8NYIkpBDaggh394JYJiwIKcg0xD5YAFhTxF_Qc":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":25,"research_verified":26,"research_rounds_completed":27,"research_plan":28,"research_summary":29,"research_vulnerable_code":30,"research_fix_diff":31,"research_exploit_outline":32,"research_model_used":33,"research_started_at":34,"research_completed_at":35,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":26,"poc_model_used":9,"poc_verification_depth":9,"source_links":36},"CVE-2026-2305","addfunc-head-footer-code-authenticated-contributor-stored-cross-site-scripting-via-custom-fields","AddFunc Head & Footer Code \u003C= 2.3 - Authenticated (Contributor+) Stored Cross-Site Scripting via Custom Fields","The AddFunc Head & Footer Code plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the `aFhfc_head_code`, `aFhfc_body_code`, and `aFhfc_footer_code` post meta values in all versions up to, and including, 2.3. This is due to the plugin outputting these meta values without any sanitization or escaping. While the plugin restricts its own metabox and save handler to administrators via `current_user_can('manage_options')`, it does not use `register_meta()` with an `auth_callback` to protect these meta keys. This makes it possible for authenticated attackers, with Contributor-level access and above, to inject arbitrary web scripts via the WordPress Custom Fields interface that execute when an administrator previews or views the post.","addfunc-head-footer-code",null,"\u003C=2.3","2.4","medium",6.4,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-04-09 14:51:35","2026-04-10 03:35:35",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F2f2d1a67-1d9b-4b73-988e-085eaa7474c6?source=api-prod",1,[22,23,24],"addfunc-head-footer-code.php","options.php","readme.txt","researched",false,3,"# Exploitation Research Plan - CVE-2026-2305\n\n## 1. Vulnerability Summary\nThe **AddFunc Head & Footer Code** plugin (version \u003C= 2.3) is vulnerable to **Authenticated Stored Cross-Site Scripting (XSS)**. The plugin allows administrators to add custom scripts to the `\u003Chead>`, start of the `\u003Cbody>`, and `\u003Cfooter>` sections of specific posts via three meta keys: `aFhfc_head_code`, `aFhfc_body_code`, and `aFhfc_footer_code`. \n\nWhile the plugin restricts its custom UI (metaboxes) to users with the `manage_options` capability, it fails to protect these meta keys using `register_meta()` with an `auth_callback`. Because the meta keys do not start with an underscore (e.g., `_aFhfc_head_code`), they are considered \"public\" by WordPress. Consequently, any user with `edit_posts` capability (Contributor level and above) can use the default WordPress **Custom Fields** interface to create or update these meta values, injecting arbitrary JavaScript that executes whenever the post is viewed.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: `wp-admin\u002Fpost.php`\n- **Action**: `editpost`\n- **Vulnerable Parameters**: `addmeta[1][key]` (set to `aFhfc_head_code`, `aFhfc_body_code`, or `aFhfc_footer_code`) and `addmeta[1][value]` (the payload).\n- **Authentication Level**: Authenticated (Contributor or higher). Contributors can edit their own posts and manage custom fields for them.\n- **Preconditions**: The WordPress site must have \"Custom Fields\" enabled in the post editor (standard behavior).\n\n## 3. Code Flow\n1. **Injection**: \n   - A Contributor-level user sends a POST request to `wp-admin\u002Fpost.php` with `action=editpost`.\n   - The request includes a new custom field: `aFhfc_head_code` with a malicious script.\n   - WordPress core's `edit_post()` function processes the `addmeta` array and saves the value to the `wp_postmeta` table because the key is not protected.\n\n2. **Execution (Head)**:\n   - `addfunc-head-footer-code.php` registers a hook: `add_action('wp_head', array('aFHFCClass','output_head_code'))`.\n   - When the post is viewed, `aFHFCClass::output_head_code()` is called.\n   - It fetches the value: `$meta_head_code = get_post_meta(get_the_ID(),'aFhfc_head_code',true);`.\n   - It outputs the value raw: `echo $meta_head_code.\"\\n\";` (Line 66).\n\n3. **Execution (Body\u002FFooter)**:\n   - Similar flows exist for `aFhfc_body_code` (Line 78) and `aFhfc_footer_code` (Line 89).\n\n## 4. Nonce Acquisition Strategy\nThe exploitation uses the standard WordPress post-editing flow, which requires a core WordPress nonce (`_wpnonce`), not a plugin-specific one.\n\n1. **Navigate to Edit Page**: Use `browser_navigate` to go to the edit page of a post owned by the Contributor: `wp-admin\u002Fpost.php?post=POST_ID&action=edit`.\n2. **Extract Nonce**: Use `browser_eval` to extract the `_wpnonce` value from the form.\n   - Script: `document.querySelector('input[name=\"_wpnonce\"]').value`\n3. **Alternative**: If the \"Custom Fields\" metabox is not visible, it might need to be enabled via the \"Screen Options\" (Classic Editor) or \"Preferences\" (Gutenberg), but the POST request to `post.php` works regardless of UI visibility if the ID and nonce are correct.\n\n## 5. Exploitation Strategy\nThe goal is to inject a script into the `\u003Chead>` of a post created by a Contributor.\n\n1. **Setup User**: Create a Contributor user and a post.\n2. **Obtain Nonce**: Log in as the Contributor, navigate to the post's edit page, and grab the `_wpnonce`.\n3. **Inject Payload**:\n   - Send a POST request to `\u002Fwp-admin\u002Fpost.php` using the `http_request` tool.\n   - **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n   - **Body**:\n     ```\n     action=editpost\n     &post_ID=[POST_ID]\n     &_wpnonce=[NONCE]\n     &addmeta[1][key]=aFhfc_head_code\n     &addmeta[1][value]=\u003Cscript>alert('XSS_HEAD')\u003C\u002Fscript>\n     ```\n4. **Trigger**: Navigate to the frontend URL of the post (`?p=[POST_ID]`) as any user (including an unauthenticated guest).\n\n## 6. Test Data Setup\n1. **Contributor User**: \n   - Username: `low_priv_user`\n   - Role: `contributor`\n2. **Target Post**:\n   - Title: `Vulnerable Post`\n   - Author: `low_priv_user`\n   - Note the `POST_ID`.\n\n## 7. Expected Results\n- The POST request to `post.php` should return a `302 Redirect` back to the edit page (indicating success).\n- When fetching the frontend post page, the source code should contain `\u003Cscript>alert('XSS_HEAD')\u003C\u002Fscript>` inside the `\u003Chead>` tags.\n\n## 8. Verification Steps\n1. **Verify Database Storage**:\n   - Use WP-CLI: `wp post meta get [POST_ID] aFhfc_head_code`.\n   - Confirm it contains the `\u003Cscript>` payload.\n2. **Verify Frontend Execution**:\n   - Use `http_request` (GET) on the post's permalink.\n   - Check if the payload exists in the response body.\n\n## 9. Alternative Approaches\nIf `aFhfc_head_code` is sanitized by a security plugin or WAF, attempt the other keys:\n- **Body Start Injection**: Use `aFhfc_body_code`. This is particularly dangerous as it uses `preg_replace` to inject immediately after the `\u003Cbody>` tag (Line 115).\n- **Footer Injection**: Use `aFhfc_footer_code`, which outputs during the `wp_footer` action.\n\nIf the site uses Gutenberg and the `post.php` method is restricted, the same can be achieved via the REST API if the meta is registered (though the vulnerability exists specifically because it *isn't* registered correctly):\n- **Endpoint**: `POST \u002Fwp-json\u002Fwp\u002Fv2\u002Fposts\u002F[POST_ID]`\n- **Body**: `{\"meta\": {\"aFhfc_head_code\": \"\u003Cscript>alert(1)\u003C\u002Fscript>\"}}`\n*Note: This only works if WordPress considers the meta key \"rest-visible\", which usually requires registration.* Therefore, the `post.php` (Classic\u002FHeartbeat) method is the most reliable.","The AddFunc Head & Footer Code plugin for WordPress is vulnerable to Authenticated (Contributor+) Stored Cross-Site Scripting via the 'aFhfc_head_code', 'aFhfc_body_code', and 'aFhfc_footer_code' post meta values. This occurs because the plugin fails to sanitize or escape these values before outputting them and does not protect the meta keys via register_meta(), allowing users with post-editing privileges to inject scripts through the WordPress Custom Fields interface.","\u002F\u002F addfunc-head-footer-code.php line 60-70\n    public static function output_head_code()\n    {\n      $site_head_code = get_option('aFhfc_site_wide_head_code');\n      $meta_head_code = ((is_archive()) || (is_author()) || (is_category()) || (is_tag()) || (is_home()) || (is_search()) || (is_404())) ? '' : get_post_meta(get_the_ID(),'aFhfc_head_code',true);\n      $head_replace = get_post_meta(get_the_ID(),'aFhfc_head_replace',true);\n      if(!empty($head_replace)){\n        echo $meta_head_code.\"\\n\";\n      }else{\n        echo $site_head_code.\"\\n\".$meta_head_code.\"\\n\";\n      }\n    }\n\n---\n\n\u002F\u002F addfunc-head-footer-code.php line 84-94\n    public static function output_footer_code()\n    {\n      $site_footer_code = get_option('aFhfc_site_wide_footer_code');\n      $meta_footer_code = ((is_archive()) || (is_author()) || (is_category()) || (is_tag()) || (is_home()) || (is_search()) || (is_404())) ? '' : get_post_meta(get_the_ID(),'aFhfc_footer_code',true);\n      $footer_replace = get_post_meta(get_the_ID(),'aFhfc_footer_replace',true);\n      if(!empty($footer_replace)){\n        echo $meta_footer_code.\"\\n\";\n      }else{\n        echo $site_footer_code.\"\\n\".$meta_footer_code.\"\\n\";\n      }\n    }","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Faddfunc-head-footer-code\u002F2.3\u002Faddfunc-head-footer-code.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Faddfunc-head-footer-code\u002F2.4\u002Faddfunc-head-footer-code.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Faddfunc-head-footer-code\u002F2.3\u002Faddfunc-head-footer-code.php\t2019-05-29 19:40:24.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Faddfunc-head-footer-code\u002F2.4\u002Faddfunc-head-footer-code.php\t2026-03-28 16:08:56.000000000 +0000\n@@ -1,12 +1,13 @@\n-\u003C?php\n+\u003C?php if ( ! defined( 'ABSPATH' ) ) exit;\n \u002F*\n     Plugin Name: AddFunc Head & Footer Code\n     Plugin URI:\n     Description: Allows administrators to add code to the &lt;head&gt; and\u002For &lt;footer&gt; of an individual post and\u002For site-wide. Ideal for scripts such as Google Analytics conversion tracking codes and any other general or page-specific JavaScript.\n-    Version: 2.3\n+    Version: 2.4\n     Author: AddFunc\n     Author URI: http:\u002F\u002Fprofiles.wordpress.org\u002Faddfunc\n-    License: Public Domain\n+    Text Domain: addfunc-head-footer-code\n+    License: GPLv2 or later\n     @since 3.0.1\n            ______\n        _  |  ___\u002F   _ _ __   ____\n@@ -27,84 +28,93 @@\n if(!class_exists('aFHFCClass')) :\n   define('AFHDFTRCD_ID', 'aFhfc');\n   define('AFHDFTRCD_NICK', 'Head & Footer Code');\n-  class aFHFCClass\n-  {\n-    public static function file_path($file)\n-    {\n+  class aFHFCClass {\n+    public static function file_path($file) {\n       return plugin_dir_path(__FILE__).$file;\n     }\n-    public static function register()\n-    {\n+    public static function register() {\n       register_setting(AFHDFTRCD_ID.'_options', 'aFhfc_site_wide_head_code');\n       register_setting(AFHDFTRCD_ID.'_options', 'aFhfc_head_code_priority');\n       register_setting(AFHDFTRCD_ID.'_options', 'aFhfc_site_wide_body_code');\n       register_setting(AFHDFTRCD_ID.'_options', 'aFhfc_site_wide_footer_code');\n       register_setting(AFHDFTRCD_ID.'_options', 'aFhfc_footer_code_priority');\n     }\n+    public static function register_meta_keys() {\n+      register_meta('post', 'aFhfc_head_code', array(\n+        'auth_callback'     => function() { return current_user_can('manage_options'); },\n+        'sanitize_callback' => 'wp_kses_post',\n+        'show_in_rest'      => false,\n+      ));\n+      register_meta('post', 'aFhfc_body_code', array(\n+        'auth_callback'     => function() { return current_user_can('manage_options'); },\n+        'sanitize_callback' => 'wp_kses_post',\n+        'show_in_rest'      => false,\n+      ));\n+      register_meta('post', 'aFhfc_footer_code', array(\n+        'auth_callback'     => function() { return current_user_can('manage_options'); },\n+        'sanitize_callback' => 'wp_kses_post',\n+        'show_in_rest'      => false,\n+      ));\n+    }\n-    public static function menu()\n-    {\n+    public static function menu() {\n       add_options_page(AFHDFTRCD_NICK.' Plugin Options', AFHDFTRCD_NICK, 'manage_options', AFHDFTRCD_ID.'_options', array('aFHFCClass', 'options_page'));\n     }\n-    public static function options_page()\n-    {\n+    public static function options_page() {\n       if (!current_user_can('manage_options'))\n       {\n-        wp_die(__('You do not have sufficient permissions to access this page.'));\n+        wp_die(__('You do not have sufficient permissions to access this page.', 'addfunc-head-footer-code'));\n       }\n       $plugin_id = AFHDFTRCD_ID;\n       include(self::file_path('options.php'));\n     }\n-    public static function output_head_code()\n-    {\n+    public static function output_head_code() {\n       $site_head_code = get_option('aFhfc_site_wide_head_code');\n       $meta_head_code = ((is_archive()) || (is_author()) || (is_category()) || (is_tag()) || (is_home()) || (is_search()) || (is_404())) ? '' : get_post_meta(get_the_ID(),'aFhfc_head_code',true);\n       $head_replace = get_post_meta(get_the_ID(),'aFhfc_head_replace',true);\n-      if(!empty($head_replace)){\n+      if(!empty($head_replace)) {\n         echo $meta_head_code.\"\\n\";\n       }else{\n         echo $site_head_code.\"\\n\".$meta_head_code.\"\\n\";\n       }\n     }\n-    public static function output_body_code()\n-    {\n+    public static function output_body_code() {\n       $site_body_code = get_option('aFhfc_site_wide_body_code');\n       $meta_body_code = ((is_archive()) || (is_author()) || (is_category()) || (is_tag()) || (is_home()) || (is_search()) || (is_404())) ? '' : get_post_meta(get_the_ID(),'aFhfc_body_code',true);\n       $body_replace = get_post_meta(get_the_ID(),'aFhfc_body_replace',true);\n-      if(!empty($body_replace)){\n+      if(!empty($body_replace)) {\n         return $meta_body_code.\"\\n\";\n       }else{\n         return $site_body_code.\"\\n\".$meta_body_code.\"\\n\";\n       }\n     }\n-    public static function output_footer_code()\n-    {\n+    public static function output_footer_code() {\n       $site_footer_code = get_option('aFhfc_site_wide_footer_code');\n       $meta_footer_code = ((is_archive()) || (is_author()) || (is_category()) || (is_tag()) || (is_home()) || (is_search()) || (is_404())) ? '' : get_post_meta(get_the_ID(),'aFhfc_footer_code',true);\n       $footer_replace = get_post_meta(get_the_ID(),'aFhfc_footer_replace',true);\n-      if(!empty($footer_replace)){\n+      if(!empty($footer_replace)) {\n         echo $meta_footer_code.\"\\n\";\n       }else{\n         echo $site_footer_code.\"\\n\".$meta_footer_code.\"\\n\";\n       }\n     }\n   }\n-  if (is_admin())\n-  {\n+  add_action('init', array('aFHFCClass','register_meta_keys'));\n+  if (is_admin()) {\n     add_action('admin_init', array('aFHFCClass','register'));\n     add_action('admin_menu', array('aFHFCClass','menu'));\n   }","The exploit leverages the fact that the plugin's custom post meta keys (aFhfc_head_code, aFhfc_body_code, aFhfc_footer_code) are not registered with restricted permissions, allowing any user with the ability to edit a post (Contributor role and above) to modify them via the standard WordPress Custom Fields interface. An attacker logs in as a Contributor, navigates to the 'Edit Post' page for one of their posts, and adds a new Custom Field with a key such as 'aFhfc_head_code' and a value containing a malicious script (e.g., \u003Cscript>alert(1)\u003C\u002Fscript>). When the post is updated, WordPress core saves this meta value. When any user (including an administrator) subsequently views the post on the frontend, the plugin retrieves the raw script from the database and echoes it directly into the page's HTML, resulting in script execution.","gemini-3-flash-preview","2026-04-16 16:13:52","2026-04-16 16:14:16",{"type":37,"vulnerable_version":38,"fixed_version":11,"vulnerable_browse":39,"vulnerable_zip":40,"fixed_browse":41,"fixed_zip":42,"all_tags":43},"plugin","2.3","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Faddfunc-head-footer-code\u002Ftags\u002F2.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Faddfunc-head-footer-code.2.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Faddfunc-head-footer-code\u002Ftags\u002F2.4","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Faddfunc-head-footer-code.2.4.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Faddfunc-head-footer-code\u002Ftags"]