Introduction
This started for me during learning and experimentation with web security concepts, especially browser trust models, cross‑origin communication, and API access control. I was studying how browsers enforce security boundaries between websites and how servers define which origins they trust and how they handle sensitive things like token, API Keys, Credentials between these origins. So this whole blog post will be of CORS Miscofiguration.
I'll try to use simple language but include real technical details, so you don't get lost and I hope you learn something from this about getting your own CVE someday, because CVE discovery is usually imagined as advanced exploitation, complex payloads, and sophisticated tools. In reality, many real vulnerabilities start with something much simpler: observing abnormal behavior and asking why it exists. This blog post will include the concepts involved in this CVE and how its exploited.

Core Concepts
Origin (Browser Security Boundary)
In web security, an origin is the most basic unit of trust. It is created from three values: protocol, domain, and port. The browser combines these three values to decide whether two resources belong to the same security zone or not. If even one of these values is different, the browser treats them as completely separate and unrelated systems.
For example, https://site.com and http://site.com look similar to humans, but for the browser they are different origins because the protocol is different. https://site.com and https://api.site.com are also different because the domain is different. Even https://site.com:443 and https://site.com:8080 are different because the port is different.
The reason origins exist is trust separation. The browser assumes that different origins should not trust each other by default. This prevents one website from automatically accessing another website's data. Origins are therefore not just technical identifiers, they are security boundaries that define who can talk to whom and who can access what.
Same-Origin Policy (SOP)
Same-Origin Policy is the main rule that enforces these boundaries. It means that JavaScript running on one origin is not allowed to read data from another origin. This rule protects cookies, sessions, API responses, authentication tokens, and private user information.
Even if a request is successfully sent to another website, the browser will block JavaScript from reading the response unless the server explicitly allows it. This means communication is possible, but data access is restricted. SOP is what prevents a random website from reading your Gmail, bank account, or social media data through the browser.
This rule is enforced entirely by the browser. The server does not control Same-Origin Policy. The browser decides what JavaScript is allowed to access. This is why browser security models are so important in web security.
Cross-Origin Communication
Browsers allow sending requests across origins, but they separate sending from reading. A website can send a request to any server, but the browser will block access to the response data unless permission is given. This design allows APIs to exist, but still keeps user data protected.
This separation creates a security model where servers must explicitly declare trust, and browsers enforce that trust. Without this model, modern web applications would not be possible in a secure way.
CORS (Cross-Origin Resource Sharing)
CORS is the mechanism that allows servers to define which external origins they trust. It is a permission model between the server and the browser. The server sends HTTP headers that tell the browser whether a specific origin is allowed to access the resource.
CORS does not protect the server from being attacked. It only controls what the browser exposes to JavaScript. If CORS is misconfigured, the browser will willingly expose sensitive data to untrusted websites because it trusts the server's headers.
This means CORS is not a security barrier by itself. It is a trust declaration system. If trust is declared incorrectly, security collapses.
Access-Control-Allow-Origin
This header is the core of CORS. It defines which origin is allowed to read the response. In a secure system, this value is fixed and limited to known trusted domains. In an insecure system, it may allow all origins. In the most dangerous configuration, the server dynamically copies the incoming Origin header into the response.
When this happens, the server is no longer validating trust. It is blindly accepting whatever identity the requester claims to have. This completely breaks the trust model because any website can pretend to be trusted simply by setting the Origin header.
Access-Control-Allow-Credentials
This header tells the browser that it is allowed to send authentication data in cross-origin requests. When enabled, cookies and session identifiers are included in requests made to other origins.
If this is combined with weak origin validation, it allows external websites to send fully authenticated requests as the victim user. This effectively turns the browser into an authenticated attack proxy.
Authentication, Cookies, and Sessions
Browsers store user authentication using cookies, session identifiers, and sometimes tokens. These values represent the user's identity and permissions. When a user is logged into a website, these authentication values are automatically attached to requests made by the browser.
This means that any request sent by the browser can become an authenticated request if credentials are included. The browser does not ask the user each time. It automatically attaches identity data.
Preflight Requests
For sensitive operations, browsers use preflight requests. These are OPTIONS requests that ask the server whether a certain origin, method, and header combination is allowed. If the server approves, the browser sends the real request.
If the server is misconfigured, the preflight system becomes meaningless because the browser will approve dangerous requests automatically.
Trust Boundary Model
In a secure design, the browser enforces access rules and the server validates trust decisions. In this vulnerability, the server does not validate trust and the browser blindly follows the server's instructions. This reverses the security model and removes the protection layer entirely.
Initial Observation
Strapi is a Open-Source Headless CMS for AI powered Websites and Apps used by various organisations like IBM, Accenture, Toyota, TATA, Walmart, NASA and many more.
After understanding how CORS and browser trust models work, I started doing basic manual testing using raw HTTP requests on Strapi. The goal was not exploitation, but observation. I wanted to see how the server reacts when the Origin header changes and how it decides which origins are trusted.
Normal Request
GET /api/test HTTP/1.1
Host: target.com
Origin: https://test.com
User-Agent: Mozilla/5.0
Accept: application/jsonResponse:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://test.com
Access-Control-Allow-Credentials: true
Content-Type: application/jsonlooks normal, right?
Modified Origin Request
I changed only one thing — the Origin header:
GET /api/test HTTP/1.1
Host: target.com
Origin: https://evil.com
User-Agent: Mozilla/5.0
Accept: application/jsonResponse:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://evil.com
Access-Control-Allow-Credentials: true
Content-Type: application/jsonThe server reflected the origin value directly.
This means the server trusted attacker-controlled input to define security policy.
This behavior is called origin reflection and it breaks the trust model.
At this point, I knew this was not a normal configuration. A secure server should never trust user-controlled input to decide security policy. The Origin header is fully controlled by the client, which means it should never be trusted without validation.
This observation was the first real signal that a security boundary was broken.
Technical Root Cause
The root cause was a simple logic flaw in configuration and trust validation.
The server was dynamically generating the Access-Control-Allow-Origin header based directly on the incoming Origin header. In logical terms, the behavior was equivalent to:
Access-Control-Allow-Origin = request.headers["Origin"]
There was no whitelist. There was no validation. There was no filtering. There was no trust check.
This means that any website in the world could claim to be a trusted origin simply by setting its Origin header to any value. The server did not verify identity. It only mirrored input.
This breaks the fundamental security assumption that trust decisions must never be based on user-controlled input.
How This Breaks Browser Security
Browsers rely on server-provided CORS headers to decide whether JavaScript is allowed to read cross-origin responses. The browser assumes that the server is making a correct trust decision.
When the server reflects arbitrary origins, the browser interprets this as a valid trust declaration. The browser then allows JavaScript from that origin to read the response data.
If Access-Control-Allow-Credentials is also enabled, the browser will include cookies and session identifiers in the request. This transforms the request into an authenticated user request.
At that point, the browser is no longer acting as a security barrier. It becomes a transport mechanism for authenticated data extraction.
Exploitation Logic
The exploitation does not require malware, payloads, or vulnerability chains. It relies purely on normal browser behavior.
A user logs into the vulnerable application. Their browser stores authentication cookies. The user then visits an attacker-controlled website. That website runs JavaScript in the victim's browser. The JavaScript sends a cross-origin request to the vulnerable server. The browser automatically attaches cookies. The server trusts the attacker's origin. The server returns sensitive data. The malicious website reads the response. In case of Strapi, it shared the admin token to my controlled site.
This entire flow happens inside the browser. No security alerts are triggered. No suspicious binaries are executed. No exploit code is injected. The browser follows protocol rules exactly as designed.
Proof-of-Concept Explanation
A simple fetch request is enough to exploit this behavior:
fetch("https://target.com/api/private", {
credentials: "include"
})
.then(r => r.text())
.then(data => console.log(data));This works because the server tells the browser that the attacker's website is trusted and that credentials are allowed. The browser obeys the server's trust declaration.
Impact Analysis
This vulnerability allows attackers to extract sensitive data directly from authenticated user sessions. The severity depends on the exposed endpoints, but the technical impact includes unauthorized API access, session-based data leakage, private information disclosure, and cross-site data extraction.
The danger is not the exploit complexity. The danger is the trust model failure.
Disclosure Process
After confirming the behavior, I documented the request and response patterns, captured technical evidence, explained the security impact, and created reproducible steps and forwaded them to Strapi.
The vulnerability was reported responsibly. The maintainers validated the issue, fixed the configuration logic, and coordinated disclosure.
An official CVE identifier was assigned to this vulnerability: CVE-2025–53092.
https://nvd.nist.gov/vuln/detail/CVE-2025-53092
Message for Beginners
You don't need advanced exploitation skills to find vulnerabilities.
You need understanding of systems, protocols, trust models, and how components interact.
Learn how browsers work. Learn how servers work. Learn how trust is defined.
That is where real vulnerabilities live. This CVE proves that anyone who studies fundamentals, asks questions, and tests systems can contribute to real-world security.
I was not able to cover this with a live target of Strapi because of tight schedules cuz I might need to install Strapi and set it up with the vulnerable version, but with most of the things that you read here its almost similar to in case of Strapi.
Thank You!
My LinkedIn: https://www.linkedin.com/in/ghostvirus
My Github: https://github.com/ghostvirus62