Summary
A logged-out AJAX request whose action parameter is submitted as an array can cause Optimole to terminate with a strpos() TypeError during startup.
Expected behavior: the request is handled or rejected without an Optimole fatal error.
Actual behavior: Optimole passes the array value to strpos(), producing a fatal error before the request completes.
Impact: affected frontend AJAX requests fail with a 500 response while Optimole is enabled and connected.
Customer context
- Product / area: Optimole WordPress plugin, AJAX request detection
- Version: 4.2.12
- Environment: WordPress 7.1, PHP 8.3.33
- Integration / third party: Not provided
- Reported error / symptom:
strpos(): Argument #1 ($haystack) must be of type string, array given
- Impact: 20 telemetry occurrences across 2 production sites between 2026-09-12 08:35 and 15:01 UTC.
Reproduction notes
Reported production context: frontend requests on Optimole 4.2.12, WordPress 7.1, and PHP 8.3.33.
- Enable and connect Optimole.
- Send a logged-out AJAX request with an array-valued
action parameter, such as action[]=wpmdb.
- During Optimole startup, the request reaches AJAX detection and the reported
strpos() TypeError occurs.
Direct PHP evaluation of the reported expression with an array argument produced the same TypeError. A full WordPress request reproduction was not run.
Diagnosis
Conclusion
Production telemetry identifies a TypeError at Optml_Manager::is_ajax_request(). The inspected v4.2.12 source passes $_REQUEST['action'] directly to strpos() after only checking that the key exists. PHP represents action[]=wpmdb as an array, which matches the reported argument type and produces the fatal on PHP 8.3.
Where this likely occurs
- Frontend AJAX startup path in
inc/manager.php — Optml_Manager::should_replace() lines 296-370 calls Optml_Manager::is_ajax_request() at lines 309-311.
inc/manager.php — Optml_Manager::is_ajax_request() lines 377-401 reaches strpos( $_REQUEST['action'], 'wpmdb' ) at line 396 without a scalar-type check.
- The call is reachable for logged-out AJAX requests:
inc/manager.php — Optml_Manager::is_ajax_request() lines 382-400 returns before this expression only when the user is logged in, AJAX is unavailable, or the request is not AJAX.
- The expression exists in release tag
v4.2.12 (ce4220e93d2a9cf83aa4351540df4e9255d028f3). Git blame attributes the line to 02df07746 from 2019; no earlier working release boundary was established.
Engineering notes
- The confirmed path is limited to AJAX requests while the visitor is logged out and Optimole is connected and enabled; these are the observed guards in the inspected code.
- A request such as
action[]=wpmdb is a plausible trigger because PHP converts bracketed request keys into arrays. WordPress core behavior after plugin initialization was not inspected locally; the telemetry and code order establish that Optimole evaluates this parameter during startup.
- This is distinct from the four file/class loading crashes in the same telemetry batch. Those traces were assessed independently and are not represented by this entry.
Test coverage status
phpunit.xml registers the tests/ PHPUnit suite. No relevant coverage was found during inspection for Optml_Manager::is_ajax_request(), an array-valued $_REQUEST['action'], or the wpmdb exclusion. tests/test-cache-header.php is manager-adjacent but covers unrelated cache-header behavior.
What to verify or explore next
- May be worth reproducing against a WordPress AJAX request with
action[]=wpmdb on supported PHP versions.
- May be worth running the PHPUnit suite and checking whether request-shape coverage exists outside the inspected
tests/ paths.
- May be worth confirming behavior with non-
wpmdb array action values and with logged-in versus logged-out requests.
Unknowns / follow-up
- Telemetry does not retain the original request payload, so the exact submitted array shape is unavailable.
- No precise open GitHub issue was found through repository issue search.
Confidence
Confidence: 97/100
v4.2.12 passes an array-capable $_REQUEST['action'] value directly to strpos() on a reachable logged-out AJAX path, matching the production TypeError. The other four crashes reference files or an SDK class present and mapped in the inspected v4.2.11 source, so the available evidence favors incomplete or mixed deployments rather than repository defects.
Crash telemetry
|
|
| Occurrences |
20 |
| Distinct sites |
2 |
| First seen |
2026-09-12 08:35 UTC |
| Last seen |
2026-09-12 15:01 UTC |
| Crash location |
product:inc/manager.php:396 |
| Request context |
frontend |
| Inside Themeisle SDK |
no |
| Product versions |
4.2.12 |
| WP versions |
7.1 |
| PHP versions |
8.3.33 |
| SDK versions |
3.3.61 |
Source: automated crash report — optimole-wp, fingerprint dc1c56b497c01bc567b15f51e34401fc
Generated by bug-report-triage (ID: bug-report-triage_6aa63c5159bf59.34701292)
Summary
A logged-out AJAX request whose
actionparameter is submitted as an array can cause Optimole to terminate with astrpos()TypeError during startup.Expected behavior: the request is handled or rejected without an Optimole fatal error.
Actual behavior: Optimole passes the array value to
strpos(), producing a fatal error before the request completes.Impact: affected frontend AJAX requests fail with a 500 response while Optimole is enabled and connected.
Customer context
strpos(): Argument #1 ($haystack) must be of type string, array givenReproduction notes
Reported production context: frontend requests on Optimole 4.2.12, WordPress 7.1, and PHP 8.3.33.
actionparameter, such asaction[]=wpmdb.strpos()TypeError occurs.Direct PHP evaluation of the reported expression with an array argument produced the same TypeError. A full WordPress request reproduction was not run.
Diagnosis
Conclusion
Production telemetry identifies a
TypeErroratOptml_Manager::is_ajax_request(). The inspectedv4.2.12source passes$_REQUEST['action']directly tostrpos()after only checking that the key exists. PHP representsaction[]=wpmdbas an array, which matches the reported argument type and produces the fatal on PHP 8.3.Where this likely occurs
inc/manager.php—Optml_Manager::should_replace()lines 296-370 callsOptml_Manager::is_ajax_request()at lines 309-311.inc/manager.php—Optml_Manager::is_ajax_request()lines 377-401 reachesstrpos( $_REQUEST['action'], 'wpmdb' )at line 396 without a scalar-type check.inc/manager.php—Optml_Manager::is_ajax_request()lines 382-400 returns before this expression only when the user is logged in, AJAX is unavailable, or the request is not AJAX.v4.2.12(ce4220e93d2a9cf83aa4351540df4e9255d028f3). Git blame attributes the line to02df07746from 2019; no earlier working release boundary was established.Engineering notes
action[]=wpmdbis a plausible trigger because PHP converts bracketed request keys into arrays. WordPress core behavior after plugin initialization was not inspected locally; the telemetry and code order establish that Optimole evaluates this parameter during startup.Test coverage status
phpunit.xmlregisters thetests/PHPUnit suite. No relevant coverage was found during inspection forOptml_Manager::is_ajax_request(), an array-valued$_REQUEST['action'], or thewpmdbexclusion.tests/test-cache-header.phpis manager-adjacent but covers unrelated cache-header behavior.What to verify or explore next
action[]=wpmdbon supported PHP versions.tests/paths.wpmdbarray action values and with logged-in versus logged-out requests.Unknowns / follow-up
Confidence
Confidence: 97/100
v4.2.12passes an array-capable$_REQUEST['action']value directly tostrpos()on a reachable logged-out AJAX path, matching the production TypeError. The other four crashes reference files or an SDK class present and mapped in the inspectedv4.2.11source, so the available evidence favors incomplete or mixed deployments rather than repository defects.Crash telemetry
product:inc/manager.php:396Source: automated crash report — optimole-wp, fingerprint
dc1c56b497c01bc567b15f51e34401fcGenerated by bug-report-triage (ID: bug-report-triage_6aa63c5159bf59.34701292)