Aug 19, 2026·4 min read·20 visits
A validation failure in the local TinaCMS dev server allowed external websites to perform arbitrary file writes inside the developer's project folder via cross-origin multipart form uploads.
A Cross-Site Request Forgery (CSRF) vulnerability in the local development server of @tinacms/cli allowed malicious cross-origin pages to send state-changing HTTP requests. This issue permitted attackers to write arbitrary files into a developer's project directory or manipulate search and GraphQL indices without authorization.
The @tinacms/cli package includes a local development server intended to run during project editing phases. This development server typically binds to local ports such as http://localhost:4001 to process API operations. To support development workflows, the server exposes state-changing endpoints like /media/upload for managing asset uploads, as well as GraphQL and search index endpoints.
While the server utilized standard Cross-Origin Resource Sharing (CORS) configurations, it relied on these mechanisms as an access control boundary. This design choice overlooked the functional limits of browser CORS policies, which govern read restrictions rather than write blocks. Consequently, the local server was exposed to cross-origin requests dispatched by external pages opened in the developer's browser, bypassing standard CORS origin protections.
The fundamental flaw in @tinacms/cli is the conceptual misuse of CORS middleware for server-side request filtering. The server leveraged the npm cors package to evaluate the Origin header. However, CORS standard behaviors indicate that the Access-Control-Allow-Origin headers only restrict the calling web application's ability to read responses; they do not prevent browsers from executing requests.
Under standard browser semantics, a POST request using multipart/form-data is categorized as a "simple request." As a result, the browser skips sending a preflight OPTIONS request and directly transmits the POST payload to the target local server. Although the browser eventually blocks the malicious page from reading the response due to the lack of appropriate CORS headers, the server-side state-changing code—such as the file write routine inside mediaRouter.handlePost—executes to completion. This leaves the developer vulnerable to silent file injection.
In vulnerable versions, the route plugins for the Vite dev server processed inbound requests regardless of origin validation results. The cors check only appended headers but never aborted processing. The fix introduces a structured isOriginAllowed logic step that performs active server-side gating.
// Server-Side Origin Guarding Implementation
export function isOriginAllowed(
origin: string | undefined,
allowedOrigins: (string | RegExp)[] = []
): boolean {
// Allow requests with no Origin header (curl, same-origin, etc.)
if (!origin) {
return true;
}
if (LOCALHOST_RE.test(origin)) {
return true;
}
for (const allowed of expandOrigins(allowedOrigins)) {
if (typeof allowed === 'string') {
if (allowed === origin) {
return true;
}
} else {
allowed.lastIndex = 0;
if (allowed.test(origin)) {
return true;
}
}
}
return false;
}The routes now actively evaluate each transaction using isStateChangingRequest() and reject unauthorized requests immediately:
// Gating inside plugins.ts
const isStateChangingRequest = (req: { url?: string; method?: string }) => {
const url = req.url || '';
if (url.startsWith('/media/upload')) return true;
if (url.startsWith('/media') && req.method === 'DELETE') return true;
if (url.startsWith('/graphql') && req.method === 'POST') return true;
if (
(url.startsWith('/searchIndex') || url.startsWith('/v2/searchIndex')) &&
(req.method === 'POST' || req.method === 'DELETE')
)
return true;
return false;
};
// Gating check prior to parsing execution
if (
isStateChangingRequest(req) &&
!isOriginAllowed(req.headers.origin, allowedOrigins)
) {
res.statusCode = 403;
res.end(JSON.stringify({ error: 'Origin not allowed' }));
return;
}To exploit this vulnerability, an attacker must trick a developer who has an active local tinacms dev instance running into visiting a malicious site. The malicious site hosts JavaScript that initiates a background HTTP POST request targeting http://localhost:4001/media/upload/payload.js.
The payload uses standard web APIs to generate a multipart/form-data payload containing arbitrary code. Because the browser classifies this as a simple request, the browser submits the multipart payload directly to the localhost server. The server, lacking origin checks, executes the write handler and drops the arbitrary file into the local workspace directory.
The concrete security impact is high-severity local file manipulation. Since the development server can write arbitrary files to the media root or local folders, an attacker can overwrite crucial configuration parameters, template structures, or executable scripts in modern build configurations.
Depending on the specific file system layout and build pipeline configurations, a malicious file write could achieve local remote code execution (RCE) on the developer's machine when compilation or local server execution cycles read the modified or written configuration files.
The primary remediation strategy is upgrading the @tinacms/cli dependencies to a secure version. Upgrade the package to version 2.5.2 or later to ensure the server-side origin validations are active.
As a secondary security measure, developers should ensure that local dev servers are bound strictly to local loopback interfaces (e.g., 127.0.0.1 or [::1]) rather than public or shared network interfaces.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
@tinacms/cli TinaCMS | < 2.5.2 | 2.5.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-352 (Cross-Site Request Forgery) |
| Attack Vector | Network (Unauthenticated, requiring User Interaction) |
| CVSS Base Score | 6.5 |
| Impact | High Integrity Impact (Arbitrary File Write) |
| Exploit Status | Proof-of-Concept |
| CISA KEV Status | Not Listed |
The application does not prove or verify that a request was intentionally sent by the user, allowing unauthorized state-changing operations.
An LDAP injection vulnerability exists in the centraldogma-server-auth-shiro module of LY Corporation Central Dogma before version 0.84.0. The search logic dynamically constructs LDAP search filters by interpolating user-provided usernames without escaping RFC 4515 metacharacters. Unauthenticated remote attackers can leverage this flaw to bypass authentication, enumerate directory hierarchies, and access unauthorized resources.
CVE-2026-11746 is a critical vulnerability in Central Dogma Server prior to version 0.84.0, where an embedded ZooKeeper replication secret silently falls back to a publicly known, hard-coded default string ('ch4n63m3'). Remote attackers with access to the replication network can authenticate as legitimate cluster peers, potentially leading to unauthorized data exposure, state manipulation, or complete cluster takeover.
A logical verification flaw in ZITADEL's external JWT Identity Provider validation allows attackers to bypass session expiration checks. If an incoming JWT lacks the 'exp' claim, the system skips validation entirely, creating an indefinitely valid session. This issue has been addressed in versions 3.4.12 and 4.15.2.
CVE-2026-59149 identifies a directory traversal vulnerability in `@mockoon/commons-server`, the backend mock-server library powering the Mockoon application. The flaw occurs in the path containment validation logic used during raw file response generation. An unauthenticated attacker can exploit this weakness to retrieve arbitrary files from sibling directories sharing a common prefix with the designated static base directory.
An in-depth analysis of CVE-2026-59148, a high-severity flaw in Mockoon where unauthenticated administrative endpoints and a wildcard Cross-Origin Resource Sharing (CORS) policy allow remote execution, state poisoning, and credential theft.
An improper authentication vulnerability (CWE-287) in ZITADEL's external identity provider handler before version 4.15.3 allows remote attackers to perform complete account takeover. When auto-linking by email is enabled, ZITADEL verifies that the local target account has a verified email address but fails to verify if the external provider confirmed ownership of that same email. Attackers can exploit this by registering an unverified account with a victim's email address on a permissive external provider, leading to unauthorized account binding and persistent access.