# [CRIT] [GHSA / CRITICAL] CVE-2026-27886: Strapi may leak sensitive data via relational filtering due to lack of query sanitization

**Source:** GitHub Security Advisories
**Published:** 2026-05-14
**Article:** https://github.com/advisories/GHSA-rjg2-95x7-8qmx

## Threat Profile

Strapi may leak sensitive data via relational filtering due to lack of query sanitization

### Summary of CVE-2026-27886 Vulnerability Details

- CVE: CVE-2026-27886
- CVSS v3.1 Vector: `CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N` (9.3 — Critical)
- Affected Versions: `@strapi/strapi` <=5.36.1
- How to Patch: Immediately update your Strapi to >=5.37.0

### Description of CVE-2026-27886

Strapi versions prior to 5.37.0 did not sufficiently sanitize query parameters when filte…

## Indicators of Compromise (high-fidelity only)

- **CVE:** `CVE-2026-27886`

## MITRE ATT&CK Techniques

- **T1190** — Exploit Public-Facing Application
- **T1212** — Exploitation for Credential Access
- **T1110.001** — Password Guessing
- **T1078** — Valid Accounts
- **T1098** — Account Manipulation

## Kill chain phases observed

_(none detected from narrative keywords)_

## Recommended hunts

### Strapi CVE-2026-27886 exploit — `where[admin-relation][private-field]` query parameter against public Content API

`UC_305_1` · phase: **exploit** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime values(Web.uri_query) as queries values(Web.url) as urls values(Web.http_user_agent) as user_agents values(Web.status) as statuses from datamodel=Web where (Web.uri_query="*where[updatedBy]*" OR Web.uri_query="*where[createdBy]*" OR Web.uri_query="*where[publishedBy]*") by Web.src, Web.dest, Web.uri_path, Web.http_method | `drop_dm_object_name(Web)` | eval is_strapi_exploit=if(match(queries, "where\[(updatedBy|createdBy|publishedBy)\]\[(email|password|resetPasswordToken|confirmationToken|firstname|lastname|preferedLanguage)\]\[\$(startsWith|contains|eq|gt|lt|ge|le|in|notIn|notNull|null)\]="), 1, 0) | where is_strapi_exploit=1 | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)` | table firstTime, lastTime, src, dest, uri_path, http_method, queries, user_agents, statuses, count
```

### Strapi boolean-oracle hex-alphabet brute force from single source

`UC_305_2` · phase: **exploit** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count values(Web.uri_query) as sample_queries dc(Web.uri_query) as distinct_queries min(_time) as firstTime max(_time) as lastTime values(Web.http_user_agent) as user_agents from datamodel=Web where (Web.uri_query="*where[updatedBy]*" OR Web.uri_query="*where[createdBy]*" OR Web.uri_query="*where[publishedBy]*") AND Web.uri_query="*$*" by Web.src, Web.dest, Web.uri_path | `drop_dm_object_name(Web)` | eval duration_sec=lastTime-firstTime | where count >= 50 AND distinct_queries >= 16 AND duration_sec <= 1800 | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)` | table firstTime, lastTime, src, dest, uri_path, count, distinct_queries, duration_sec, user_agents, sample_queries
```

### Strapi CVE-2026-27886 admin takeover — exploit burst followed by `/admin/reset-password` POST

`UC_305_3` · phase: **actions** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count values(Web.uri_query) as exploit_queries from datamodel=Web where (Web.uri_query="*where[updatedBy]*" OR Web.uri_query="*where[createdBy]*" OR Web.uri_query="*where[publishedBy]*") by Web.dest, Web.src, _time span=10m | `drop_dm_object_name(Web)` | eval is_exploit=if(match(exploit_queries, "where\[(updatedBy|createdBy|publishedBy)\]\[(email|password|resetPasswordToken|confirmationToken|firstname|lastname|preferedLanguage)\]\[\$"), 1, 0) | where is_exploit=1 | rename count as exploit_count | join type=inner dest [| tstats `summariesonly` count as reset_count values(Web.http_method) as methods values(Web.src) as reset_src from datamodel=Web where Web.uri_path="*/admin/reset-password*" Web.http_method=POST by Web.dest, _time span=10m | `drop_dm_object_name(Web)`] | where exploit_count >= 10 AND reset_count >= 1 | table _time, dest, src, exploit_count, reset_count, reset_src, methods, exploit_queries
```

### IOC-driven hunts (use shared templates)

These are standard IOC-substitution hunts — the canonical SPL and KQL live once in [`_TEMPLATES.md`](../_TEMPLATES.md), so we don't repeat the same boilerplate on every CVE / hash / network-IOC briefing.

- **Asset exposure — vulnerability matches article CVE(s)** ([template](../_TEMPLATES.md#asset-exposure)) — phase: **recon**, confidence: **High**
  - CVE(s): `CVE-2026-27886`


## Why this matters

Severity classified as **CRIT** based on: CVE present, 4 use case(s) fired, 5 technique(s) inferred. Read the full article for actor attribution, tooling details, and any defanged IOCs in the body that aren't visible in the RSS summary.
