Why?
Last time, I gave two review checks a name.
- OKPN (One Kind Per Name) — one name takes one kind of value
- OMPV (One Meaning Per Value) — one value carries one meaning
- Bonus: Null Trap — if there is no value, leave the element out instead of writing null
Then it hit me: "So what actually happens if you ignore them?"
What did I do?
I picked four big recent cases (vulnerabilities and an outage) where the data shape seemed to play a part, and had Claude check them with me against primary sources.
| # | Case | Type | Principle it smells of |
|---|---|---|---|
| 1 | Next.js middleware authorization bypass | Vulnerability | OKPN |
| 2 | React2Shell | Vulnerability | OKPN |
| 3 | OttoKit authentication bypass | Vulnerability | OMPV |
| 4 | Google Cloud global outage | Outage | Null Trap |
A disclaimer first: none of these incidents has a single cause.
I'm not saying "follow OKPN/OMPV and you would have been safe."
I'm saying "a messy data shape was the trigger, or the way in."
What happened?
OKPN: pack things into one value, and attackers pack things in too
1. Next.js middleware authorization bypass (CVE-2025-29927, March 2025)
Next.js counted recursion with an internal header, x-middleware-subrequest, by packing middleware names into it, separated by colons.
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
Once the same name appeared up to the limit (5 times), Next.js thought "looks like an infinite loop, skip it" and skipped the middleware entirely.
So adding this one header from the outside made the auth check disappear.
The real problem is that an internal header could be set from the outside.
Still, packing "call history" and "the input to the skip decision" into one value smells bad through the OKPN lens.
- Primary source: Vercel: Postmortem on Next.js Middleware bypass
- Advisory: GHSA-f82v-jwr5-mffw
- Write-up: SonicWall: CVE-2025-29927
2. React2Shell (CVE-2025-55182, December 2025, CVSS 10.0)
The React Server Components wire format (Flight) expresses references by packing them into one string.
"$3:constructor:constructor"
"Chunk number 3" and "the property path to walk from there" are joined by colons into a single string.
Attackers could write any path they liked, and the server didn't check whether each property belonged to the object itself.
→ Walk constructor up to Function, and you get unauthenticated remote code execution. It was exploited in the wild.
The direct cause was missing validation during deserialization. But the shape, "parse a string and walk a path", widened the attack surface.
- Primary source: React: Critical Security Vulnerability in React Server Components
- Advisory: GHSA-fv66-9v8q-g76r
- Write-up: Pentest-Tools: Deep dive into React2Shell
OMPV / Null Trap: "empty" and "missing" broke things
3. OttoKit authentication bypass (CVE-2025-3102, April 2025, CVSS 8.1)
A WordPress plugin (formerly SureTriggers) used on about 100,000 sites.
On sites with no API key configured, sending an empty st_authorization header passed authentication and let attackers create administrator accounts. Attacks started within hours of disclosure.
The empty string was treated like a normal key, so it could no longer be told apart from "no key configured". Compare empty with empty, and they match.
The direct cause was a missing empty-value check. But ask the OMPV question, "are we giving the empty string a meaning?", and this one gets caught.
- CVE record: CVE-2025-3102 (CIRCL)
- Write-up: BleepingComputer: Hackers exploit WordPress plugin auth bypass hours after disclosure
The next one is an outage (an availability incident), not an attack. There is no CVE, so the primary source is Google's incident report.
4. Google Cloud global outage (June 12, 2025)
Policy data was pushed to Service Control, which handles quotas. That data contained unintended blank fields.
A newly added check didn't expect blank fields and crashed on a null pointer. The data reached every region within seconds, so every region went into a crash loop.
APIs returned 503, and many Google Cloud and Workspace services went down.
Nobody had defined, in the spec or in the code, "what does a blank field mean?" A classic Null Trap.
- Primary source: Google Cloud Service Health: Incident report
Is it worth it?
Very much so. Of course, OKPN/OMPV alone won't prevent incidents.
But asking these questions in a review makes dangerous shapes easier to spot. For these four cases, here are the smells that would catch them.
| Principle | Bad example (this article's incidents) |
|---|---|
| OKPN | Next.js: packed middleware:middleware:... into a header value / React2Shell: packed a reference and a path into "$3:constructor:constructor"
|
| OMPV | OttoKit: the empty string was treated as a normal value and could no longer be told apart from "no key configured" |
| Null Trap | Google Cloud: no defined handling for blank fields, so a null pointer |
All you do is ask the questions from last time's checklist in your reviews.
Checklist (copy and paste)
- OKPN: Does each name of a data element take values of one kind only? (No two values packed with a separator.)
- OMPV: Does each value of a data element have one meaning only? (No second meaning added to a special value.)
- Null Trap: Does the specification define how an omitted data element and a null value are handled, and does the implementation follow it? (No value -> omit it.)
- Exception: Where a referenced standard defines the specification of a data element, conform to that specification.
Let an AI write your code, and it will happily pack values with separators and return null.
The easiest shape today is usually the most expensive one later. Turns out that holds at global scale, too.
Here's hoping more people watch out for OKPN/OMPV and make the world a little more peaceful.
Top comments (0)