Opened 2 weeks ago
Last modified 6 days ago
#65554 new defect (bug)
Connectors: only validate AI provider API keys that were submitted in the request
| Reported by: | khokansardar | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | AI | Version: | 7.0 |
| Severity: | normal | Keywords: | has-patch has-unit-tests needs-testing |
| Cc: | Focuses: | rest-api, performance |
Description
_wp_connectors_rest_settings_dispatch() validates connector API keys on rest_post_dispatch, but a POST /wp/v2/settings response returns the full settings object. Every unrelated settings save therefore re-validates each stored AI key, firing a live list-models request per provider — a synchronous external HTTP call on installs without a persistent object cache.
Fix: only validate keys present in the current request (WP_REST_Request::has_param()).
Change History (4)
This ticket was mentioned in PR #12350 on WordPress/wordpress-develop by @khokansardar.
2 weeks ago
#1
#2
follow-up:
↓ 3
@
2 weeks ago
Environment: WordPress Local
I tested this issue on a local WordPress installation.
While saving an unrelated setting through the POST /wp/v2/settings REST endpoint, I confirmed that _wp_connectors_rest_settings_dispatch() is still executed during rest_post_dispatch, even though the connector API key is not part of the current request.
This causes validation of the stored OpenAI API key on every unrelated settings save, resulting in unnecessary external API validation requests instead of validating only the keys included in the current request.
Expected Result:
Connector API keys should only be validated when the corresponding key is present in the current request using WP_REST_Request::has_param(). Saving unrelated settings should not trigger API key validation or external HTTP requests.
#3
in reply to: ↑ 2
@
2 weeks ago
Replying to sanayasir:
Environment: WordPress Local
I tested this issue on a local WordPress installation.
While saving an unrelated setting through the POST /wp/v2/settings REST endpoint, I confirmed that _wp_connectors_rest_settings_dispatch() is still executed during rest_post_dispatch, even though the connector API key is not part of the current request.
This causes validation of the stored OpenAI API key on every unrelated settings save, resulting in unnecessary external API validation requests instead of validating only the keys included in the current request.
Expected Result:
Connector API keys should only be validated when the corresponding key is present in the current request using WP_REST_Request::has_param(). Saving unrelated settings should not trigger API key validation or external HTTP requests.
Thanks for testing, @sanayasir!
Just to clarify the behaviour you're seeing: _wp_connectors_rest_settings_dispatch() running on rest_post_dispatch is expected — it's a callback registered on that hook, so it fires for every POST /wp/v2/settings response regardless of which settings were submitted. That part isn't the bug and isn't changed by the patch.
What the patch in PR #12350 changes is the validation inside that callback. The key is now only validated when it's actually present in the current request, via WP_REST_Request::has_param():
if ( $is_update && $request->has_param( $setting_name ) && is_string( $value ) && '' !== $value && 'ai_provider' === $connector_data['type'] ) { // validate / list-models request }
So on an unrelated settings save, has_param() returns false and the branch is skipped — no external validation request is fired for the stored key.
The report reads like the pre-patch behaviour, so it's possible the patch wasn't applied during testing. Could you re-test with PR #12350 applied and confirm whether an external request actually goes out? A reliable way to check is to hook pre_http_request (or watch your request log) and save an unrelated setting:
add_filter( 'pre_http_request', function ( $pre, $args, $url ) { error_log( 'Outbound HTTP during save: ' . $url ); return $pre; }, 10, 3 );
With the patch applied, saving an unrelated setting should produce no outbound validation request, while submitting an actual provider key should still validate it. This is also covered by the included tests: test_unsubmitted_key_is_not_validated(), test_submitted_invalid_key_is_discarded(), and test_submitted_valid_key_is_preserved_and_masked().
Let me know what you find — happy to dig further if you still see a request going out with the patch applied.
#4
@
6 days ago
Test Report
Environment: Docker-based local dev environment — PHP 8.5.6, MySQL 9.7, WordPress trunk.
Tested PR #12350 locally. The real AI provider connectors (OpenAI, Anthropic, Google) require companion plugins to be installed before their settings even register, which I don't have in this environment — so a raw end-to-end REST reproduction wasn't practical. Instead, I verified the fix using the unit tests included in the PR, which register a fake in-process connector and don't depend on those plugins.
Before the fix
Applied only the new test file (tests/phpunit/tests/connectors/wpConnectorsRestSettingsDispatch.php) on top of unpatched connectors.php. Result:
`
1) Tests_Connectors_WpConnectorsRestSettingsDispatch::test_unsubmitted_key_is_not_validated
A key absent from the request must not be validated or discarded.
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
-'a-valid-secret-key'
+
`
This confirms the bug: saving unrelated settings via POST /wp/v2/settings re-validates a stored AI provider key that was never submitted, and wipes it to an empty string when validation fails.
After the fix
Applied the code fix (the $request->has_param( $setting_name ) guard). All 3 new tests passed:
`
OK (3 tests, 6 assertions)
`
Also ran the full connectors suite for regressions:
`
OK (84 tests, 216 assertions)
`
Conclusion
The patch fixes the reported issue — unrelated settings saves no longer touch stored AI provider keys — and doesn't break anything else in the connectors suite. I did not test against a live AI provider (real HTTP call), so I can't confirm the outbound HTTP behavior directly, only the code path that gates it.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
_wp_connectors_rest_settings_dispatch()validated every stored AI provider key on each settings save, because the/wp/v2/settingsresponse always returns the full set of registered settings. Unrelated saves therefore triggered a live validation request to each configured provider.Validate a key only when it is present in the current request, via
WP_REST_Request::has_param(). Masking of stored keys in the response is unchanged.Props itzmekhokan.
See #65554.
Trac ticket: https://core.trac.wordpress.org/ticket/65554
## Use of AI Tools