CVE-2026-9199

Equalize Digital Accessibility Checker <= 1.42.1 - Missing Authorization to Authenticated (Author+) Arbitrary Accessibility Issue Modification via 'largeBatch' Parameter

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.43.0
Patched in
1d
Time to patch

Description

The Equalize Digital Accessibility Checker – WCAG, ADA, EAA and Section 508 compliance plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 1.42.1. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for authenticated attackers, with author-level access and above, to dismiss, ignore, or restore accessibility audit issue records belonging to posts they are not permitted to edit by supplying an issue from their own post as an authorization token to affect matching issues across the entire site. An Author-level user can exploit this by passing largeBatch=true on a dismiss-issue request referencing one of their own post's issues, causing the handler to bulk-modify all site-wide accessibility issues sharing the same 'object' value — including those belonging to administrator-owned posts.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.42.1
PublishedJune 17, 2026
Last updatedJune 18, 2026
Affected pluginaccessibility-checker

What Changed in the Fix

Changes introduced in v1.43.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-9199 (Equalize Digital Accessibility Checker) ## 1. Vulnerability Summary The **Equalize Digital Accessibility Checker** plugin (versions <= 1.42.1) is vulnerable to a missing authorization check in its REST API handler for dismissing accessibility issues. Whi…

Show full research plan

Exploitation Research Plan: CVE-2026-9199 (Equalize Digital Accessibility Checker)

1. Vulnerability Summary

The Equalize Digital Accessibility Checker plugin (versions <= 1.42.1) is vulnerable to a missing authorization check in its REST API handler for dismissing accessibility issues. While the plugin verifies that a user has permission to dismiss an issue on a post they own (Author level), it fails to properly restrict the scope when the largeBatch parameter is set to true.

An authenticated attacker with Author-level permissions can provide an issue_id belonging to their own post to pass the initial authorization check. By setting largeBatch=true, the plugin's backend logic proceeds to dismiss or modify all matching accessibility issues across the entire site (site-wide) that share the same "object" (the specific code snippet or element identifier) and rule type, including issues on posts owned by Administrators.

2. Attack Vector Analysis

  • Endpoint: /wp-json/accessibility-checker/v1/dismiss-issue/(?P<issue_id>\d+)
  • Method: POST
  • Authentication Required: Authenticated, minimum Author role (must be able to create a post and trigger an accessibility scan to generate a valid issue_id they own).
  • Payload Parameter: largeBatch=true (passed as a query parameter or POST body parameter).
  • Vulnerability Type: Missing Authorization / Improper Scope Limitation.
  • Impact: Site-wide manipulation of accessibility audit data, allowing unprivileged users to hide critical accessibility errors on sensitive pages (e.g., login pages, checkout pages, or Admin posts).

3. Code Flow

  1. Registration: The route is registered in includes/classes/class-rest-api.php.
  2. Permission Check: The permission_callback for /dismiss-issue/ checks if the user has edit_post capability for the post associated with the provided issue_id.
  3. Callback Execution: The dismiss_issue method is called.
  4. The Flaw: Inside dismiss_issue (or the underlying logic it calls), the code checks for request['largeBatch'] == 'true'.
  5. Site-wide Modification: If largeBatch is true, the plugin performs a database query (likely via $wpdb) to update all records in the accessibility issues table where the object (element hash/selector) and rule_id match the provided issue_id. This query lacks a post_id constraint, causing it to affect rows belonging to posts the Author cannot normally edit.

4. Nonce Acquisition Strategy

The REST API requires a wp_rest nonce for authenticated requests. This nonce is typically localized in the WordPress admin dashboard for use by the plugin's React/Vue components.

  1. Identify Trigger: The plugin's sidebar/metabox enqueues scripts on the post editor page.
  2. Setup: Create a test post as the Author: wp post create --post_type=post --post_status=publish --post_title="Author Post" --post_author=[AUTHOR_ID].
  3. Navigate: Use browser_navigate to go to the edit page for that post: /wp-admin/post.php?post=[POST_ID]&action=edit.
  4. Extract Nonce: Use browser_eval to extract the REST nonce from the wpApiSettings global object (standard WordPress) or the plugin's specific localized object.
    • Standard: browser_eval("window.wpApiSettings?.nonce")
    • Alternative (if plugin-specific): Check window.edac_data?.nonce or similar (inferred from accessibility-checker.php and class-rest-api.php hooks).

5. Exploitation Strategy

Step 1: Generate a Target Issue (Admin)

Create an Administrator post containing a specific accessibility violation (e.g., a link with no text).

wp post create --post_type=page --post_title="Admin Sensitive Page" --post_status=publish --post_content='<a href="https://example.com"></a>'

Note: The plugin must scan this page to populate the database. This usually happens on save or via a frontend scan.

Step 2: Generate a Reference Issue (Author)

As the Author, create a post with the exact same violation.

wp post create --post_type=post --post_title="Author Reference" --post_status=publish --post_content='<a href="https://example.com"></a>' --post_author=[AUTHOR_ID]

Step 3: Identify Author's Issue ID

Retrieve the id of the issue created in Step 2 from the database.

wp db query "SELECT id FROM wp_accessibility_checker_issues WHERE post_id = [AUTHOR_POST_ID] LIMIT 1;"

Step 4: Execute the Bypass

Send the malicious REST request using the Author's credentials and nonce.

  • URL: /wp-json/accessibility-checker/v1/dismiss-issue/[AUTHOR_ISSUE_ID]?largeBatch=true
  • Method: POST
  • Headers:
    • X-WP-Nonce: [EXTRACTED_NONCE]
    • Content-Type: application/json
  • Body: (Optional, depending on if the plugin expects dismissal reasons in 1.38.0+)
    {
      "reason": "Exploit Testing",
      "status": "dismissed"
    }
    

6. Test Data Setup

  1. User Roles:
    • An Administrator user.
    • An Author user (wp user create attacker attacker@example.com --role=author).
  2. Plugin State: Ensure "Accessibility Checker" is active and the database tables are created.
  3. Target Content: An Admin post with a "Problem" (e.g., rule_id: link_text).
  4. Attacker Content: An Author post with the same "Problem" (matching rule_id and the same HTML element/object).

7. Expected Results

  • The initial REST API call for the Author's own issue_id returns a 200 OK.
  • The response indicates that multiple issues were affected (if the plugin returns a count).
  • The accessibility issue on the Admin's post is now marked as dismissed or ignored in the database, despite the Author having no permissions for that post.

8. Verification Steps

After the HTTP request, verify the state of the Admin's issue via WP-CLI:

# Check if any issues on the Admin post are still 'active' (not dismissed)
wp db query "SELECT * FROM wp_accessibility_checker_issues WHERE post_id = [ADMIN_POST_ID] AND is_ignored = 0;"

If the query returns 0 results but the issues were previously present, the site-wide dismissal was successful.

9. Alternative Approaches

  • Restore instead of Dismiss: If the Admin has intentionally dismissed an issue, the Author can use the same largeBatch=true logic on the restore-issue endpoint (if registered separately) to reopen issues site-wide, potentially flooding the Admin's dashboard with "Problems".
  • Different Rule Types: Instead of link_text, use img_alt (missing alt text) which is a very common and easy-to-replicate violation.
  • Blind Exploitation: If the issue_id is not known, an Author can iterate through small integers for issue_id until they hit one they own, then trigger the site-wide effect.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Equalize Digital Accessibility Checker plugin (<= 1.42.1) is vulnerable to an authorization bypass where authenticated users with Author-level access can dismiss or restore accessibility issues site-wide. By providing an issue ID from a post they are authorized to edit and setting the 'largeBatch' parameter to true, attackers can bypass permission checks to modify records belonging to posts they do not own, including those of administrators.

Vulnerable Code

// includes/classes/class-rest-api.php

		// Dismiss/restore issue endpoint.
		add_action(
			'rest_api_init',
			function () use ( $ns, $version ) {
				register_rest_route(
					$ns . $version,
					'/dismiss-issue/(?P<issue_id>\d+)',
					[
						'methods'             => 'POST',
						'callback'            => [ $this, 'dismiss_issue' ],
						'args'                => [
							'issue_id'      => [
								'required'          => true,
								'validate_callback' => function ( $param ) {
									return is_numeric( $param );
								},
								'sanitize_callback' => 'absint',
							],
						],
						'permission_callback' => function ( $request ) {
							$issue_id = (int) $request['issue_id'];
							// ... Vulnerability: The handler fails to restrict the scope of the database update when largeBatch=true is supplied ...
						},
					]
				);
			}
		);

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/accessibility-checker/1.42.1/accessibility-checker.php /home/deploy/wp-safety.org/data/plugin-versions/accessibility-checker/1.43.0/accessibility-checker.php
--- /home/deploy/wp-safety.org/data/plugin-versions/accessibility-checker/1.42.1/accessibility-checker.php	2026-05-20 19:37:20.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/accessibility-checker/1.43.0/accessibility-checker.php	2026-05-29 17:19:52.000000000 +0000
@@ -10,7 +10,7 @@
  * Plugin Name:       Accessibility Checker
  * Plugin URI:        https://a11ychecker.com
  * Description:       Audit and check your website for accessibility before you hit publish. In-post accessibility scanner and guidance.
- * Version:           1.42.1
+ * Version:           1.43.0
  * Requires PHP:      7.4
  * Author:            Equalize Digital
  * Author URI:        https://equalizedigital.com
@@ -36,7 +36,7 @@
 
 // Current plugin version.
 if ( ! defined( 'EDAC_VERSION' ) ) {
-	define( 'EDAC_VERSION', '1.42.1' );
+	define( 'EDAC_VERSION', '1.43.0' );
 }
 
 // Current database version.

Exploit Outline

An authenticated attacker with Author-level permissions exploits the '/wp-json/accessibility-checker/v1/dismiss-issue/{issue_id}' endpoint. First, the attacker creates a post they own and generates an accessibility issue (e.g., a missing alt tag) to obtain a valid 'issue_id'. They then send a POST request to the dismiss-issue endpoint using this 'issue_id' and the parameter 'largeBatch=true'. The plugin's initial permission check validates the attacker's authorization to modify their own post's issue. However, because 'largeBatch' is set, the backend logic executes a bulk update targeting all issues across the entire site that share the same element signature ('object') and rule type, effectively dismissing critical accessibility findings on administrator-owned posts and sensitive pages.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.