Make WordPress Core

Opened 4 weeks ago

Closed 3 weeks ago

Last modified 2 weeks ago

#65867 closed defect (bug) (duplicate)

Connectors: AI provider API keys are re-validated on every settings update (/wp/v2/settings), causing needless provider calls and key resets

Reported by: hbhalodia Owned by: gziolo
Priority: normal Milestone:
Component: AI Version:
Severity: normal Keywords: has-patch needs-testing
Cc: Focuses:

Description

Since the Connectors feature landed in 7.0, every POST/PUT to /wp/v2/settings re-validates all stored AI provider API keys — not just the key(s) actually being saved. Because validation is a live call to the provider, any settings save (including unrelated plugin settings that use this endpoint) triggers one network round-trip per stored AI key. If a stored key fails validation at that moment (e.g. the provider is unreachable or rate-limited), the key is silently reset to an empty string.

Details

_wp_connectors_rest_settings_dispatch() is hooked on rest_post_dispatch and runs on every /wp/v2/settings response:

add_filter( 'rest_post_dispatch', '_wp_connectors_rest_settings_dispatch', 10, 3 );

On an update it iterates every connector and validates each AI-provider key found in the response data:

$is_update = 'POST' === $request->get_method() || 'PUT' === $request->get_method();

foreach ( wp_get_connectors() as $connector_id => $connector_data ) {
    ...
    $value = $data[ $setting_name ]; // $data = $response->get_data() = the FULL settings object

    if ( $is_update && is_string( $value ) && '' !== $value && 'ai_provider' === $connector_data['type'] ) {
        if ( true !== _wp_connectors_is_ai_api_key_valid( $value, $connector_id ) ) {
            update_option( $setting_name, '' );
            $data[ $setting_name ] = '';
            continue;
        }
    }
    ...
}

Two problems:

  • $data is the response of the settings controller, i.e. the entire settings object — every registered setting with its current stored value, not just the fields the client submitted. So the loop sees every connector's stored *_api_key and revalidates it.
  • The guard is only $is_update && non-empty && ai_provider; it never checks whether that particular key was part of the incoming request body.

_wp_connectors_is_ai_api_key_valid() performs a live provider call ($registry->isProviderConfigured( $provider_id ) after setting the key), so each revalidation is a network request.

Source: _wp_connectors_rest_settings_dispatch() and _wp_connectors_is_ai_api_key_valid() in Source

Steps to reproduce

  1. On a site with Connectors and an AI provider plugin active, configure and save a valid AI provider API key.
  2. Make any POST/PUT to /wp/v2/settings that does not include that key — e.g. change the Site Title, or save an unrelated plugin's settings through the same endpoint.
  3. Observe that Core revalidates the stored AI key (a provider network call fires).
  4. If that validation returns anything other than true (provider down, rate limited, transient error), the stored key is overwritten with an empty string, even though it was never submitted.

Impact

  • Unnecessary provider network calls and added latency on every settings save.
  • Affects any plugin that saves settings via /wp/v2/settings (e.g. the AI plugin).
  • Potential data loss: a valid-but-temporarily-unverifiable key can be wiped by an unrelated save.

Proposed fix

Only validate keys that were actually included in the current request payload, rather than every setting present in the response. For example, gate on the submitted params:

$submitted = (array) $request->get_json_params();

if ( $is_update
    && array_key_exists( $setting_name, $submitted )
    && is_string( $value ) && '' !== $value
    && 'ai_provider' === $connector_data['type']
) {
    // validate only keys the client actually sent
}

Masking of keys in the response should continue to apply to all settings as before; only the validate-and-revert behavior should be scoped to submitted keys.

References

AI Usage

  • Claude Code, Opus 5. Used for drafting ticket description and review the code for settings save.

Change History (11)

This ticket was mentioned in PR #13031 on WordPress/wordpress-develop by @hbhalodia.


4 weeks ago
#1

  • Keywords has-patch added

Trac ticket: https://core.trac.wordpress.org/ticket/65867

## Description

  • Fixed the issue related to settings check for API key for all connectors, even if the request does not changes or have connector key.
  • This leads to unnecessary calls to provider to check for API key on every settings save via wp/v2/settings.

## Use of AI Tools

  • Yes, Claude Code, Opus 5.
  • Used for drafting the ticket mentioned.

#2 @hbhalodia
4 weeks ago

Pinging @jeffpaul and @dkotter for the ticket review and acceptance and then we can take this forward.

Reference

#3 @hbhalodia
4 weeks ago

Related AI Plugin issue created here.

#4 @hbhalodia
3 weeks ago

Hi @jeffpaul, Let's work on this and plan to release it for the 7.2 may be? So that the unwanted settings changes does not wipe out the authentication keys from the settings.

Thanks,

@JeffPaul commented on PR #13031:


3 weeks ago
#5

@gziolo @jorgefilipecosta for your review in hopes of fixing as part of the 7.2 release cycle

#6 @JeffPaul
3 weeks ago

  • Keywords needs-testing added
  • Milestone Awaiting Review7.2

#7 @gziolo
3 weeks ago

  • Owner set to gziolo
  • Status newreviewing

#8 @gziolo
3 weeks ago

  • Milestone 7.2
  • Resolutionduplicate
  • Status reviewingclosed

Duplicate of #65554.

@gziolo commented on PR #13031:


3 weeks ago
#9

Thanks for working on this. I noticed that PR #12350, opened earlier for Trac #65554, appears to address the same underlying issue: AI provider API keys should only be validated when they were submitted in the current /wp/v2/settings request.

The regression coverage added here to the existing connectors test suite is valuable and could be carried over to #12350. Could we reconcile the two implementations and continue with one PR to avoid maintaining duplicate fixes?

@hbhalodia commented on PR #13031:


2 weeks ago
#10

Thanks for working on this. I noticed that PR #12350, opened earlier for Trac #65554, appears to address the same underlying issue: AI provider API keys should only be validated when they were submitted in the current /wp/v2/settings request.

The regression coverage added here to the existing connectors test suite is valuable and could be carried over to #12350. Could we reconcile the two implementations and continue with one PR to avoid maintaining duplicate fixes?

Thanks @gziolo, I overlooked and thinked that the issue was not created, hence gone ahead and created the new ticket. Sorry for that.

For the PRs, yes we should accomodate it to the single PR. I would ask PR author if the changes can be ported over to it, so that I can close this and work on the new one.

Unfortunately, I do not have sufficient permission to update directly to that PR.

Cc: @itzmekhokan

#11 @gziolo
2 weeks ago

In 63348:

Connectors: Only validate submitted AI provider API keys

_wp_connectors_rest_settings_dispatch() validated every stored AI provider API key on each /wp/v2/settings update, because the response always contains the full set of registered settings. Saving an unrelated setting therefore triggered a live validation request to each configured provider, and a key that failed validation at that moment was silently reset.

Validate a key only when it is present in the current request, using WP_REST_Request::has_param(). Masking of stored keys in the response is unchanged.

Add test coverage for omitted, submitted-invalid, and submitted-valid keys to the existing Tests_Connectors_WpConnectorsRestSettingsDispatch suite.

Developed in: https://github.com/WordPress/wordpress-develop/pull/12350

Props khokansardar, hbhalodia, gziolo.
Fixes #65554. See #65867.

Note: See TracTickets for help on using tickets.