CVEReports
Reports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Reports
  • Sitemap
  • RSS Feed

Company

  • About
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Powered by Google Gemini & CVE Feed

|
•

CVE-2025-68278
CVSS 7.3|EPSS 0.08%

TinaCMS: How a Blog Post Becomes a Beachhead (CVE-2025-68278)

Alon Barad
Alon Barad
Software Engineer•January 3, 2026•8 min read
PoC Available

Executive Summary (TL;DR)

A vulnerability in TinaCMS allows attackers to execute code on the server by crafting a malicious markdown file. The issue is caused by the `gray-matter` library, which processes JavaScript in frontmatter by default. Uploading a file with `---js` delimiters leads to RCE. Update to patched versions immediately to disable this functionality.

CVE-2025-68278 is a critical Remote Code Execution (RCE) vulnerability in TinaCMS, a popular headless CMS. The flaw stems from its dependency, the `gray-matter` library, which, in a stunning display of optimism, defaults to executing JavaScript or CoffeeScript found in markdown frontmatter. This allows an attacker with permission to upload a seemingly harmless markdown file to gain complete control of the server, turning a simple content update into a full-scale system compromise. The fix involves explicitly disabling these dangerous 'features,' reminding us that sometimes the most helpful libraries are the ones holding a loaded gun.

What Lurks in the Frontmatter?

TinaCMS positions itself as a slick, Git-backed headless CMS for modern development stacks. It's designed to make content management seamless for both developers and editors. At its core, it wrangles content, often stored in simple markdown files. And like most modern markdown processors, it leans heavily on frontmatter—that little block of metadata, usually YAML, at the top of a file that defines things like the title, author, and publication date.

Frontmatter is supposed to be inert data. A simple, structured key-value store that informs the static site generator how to render the page. Developers have been trained to see it as harmless configuration, as safe as a comment block. It's a trusted, foundational part of the content pipeline. Why would you ever question it?

This is where the story gets interesting. The vulnerability doesn't lie in TinaCMS's own logic, but in a dependency it trusts implicitly: gray-matter. This library is tasked with a simple job: parse the frontmatter. But it came with a hidden, and frankly, ludicrous feature. It didn't just parse data; it could also interpret and execute code. The server process, designed to handle simple text files, was unknowingly equipped with a Node.js execution engine, waiting for the right input.

The Double-Edged Sword of 'gray-matter'

The root cause of this entire mess is a classic case of a feature becoming a security nightmare. The gray-matter library, in its quest for ultimate flexibility, decided it would be a brilliant idea to support not just YAML, TOML, and JSON for frontmatter, but also JavaScript and CoffeeScript. To 'support' them, it doesn't just parse them as objects; it executes the code within the frontmatter block to generate the final metadata object.

This is CWE-94: Improper Control of Generation of Code, or 'Code Injection,' in its purest form. The library's default behavior is to trust its input so completely that it will run it with the full privileges of the parent process. It's the digital equivalent of a vending machine that accepts handwritten IOUs and dispenses cash. There's no sandbox, no warnings, just straight-up execution.

This design decision is baffling. In what universe does a content editor need to run server-side JavaScript just to define a blog post's title? It violates the principle of least astonishment, turning a data parsing library into an arbitrary code execution engine. For an attacker, this isn't a bug; it's a gift-wrapped feature, a backdoor left wide open by developers who thought they were just parsing text.

The Smoking Gun: A Tale of Two Codebases

Let's pop the hood and look at the code. The scene of the crime is packages/@tinacms/graphql/src/database/util.ts. Before the patch, the code simply called matter(), the main function from gray-matter, without specifying any engine configurations. By default, gray-matter's engine auto-detection would see the ---js delimiter and dutifully switch to its JavaScript execution engine.

The fix, committed in fa7c27abef968e3f3a3e7d564f282bc566087569, is both elegant and simple. The developers didn't try to sanitize the input or create a complex deny-list. They went straight for the kill switch. They explicitly defined a custom set of matterEngines, overriding the dangerous ones.

// The patch in packages/@tinacms/graphql/src/database/util.ts
const matterEngines = {
  // ... safe engines like toml
 
  // Disable JavaScript and CoffeeScript execution
  js: {
    parse: () => {
      throw new Error(
        'JavaScript execution in frontmatter is not allowed for security reasons'
      );
    },
    // ... same for stringify
  },
  javascript: { /* ... same override ... */ },
  coffee: { /* ... same override ... */ },
  coffeescript: { /* ... same override ... */ },
};

This change is surgical. Any attempt to parse a markdown file with ---js or ---coffee frontmatter now hits this override. Instead of executing code, the parse function immediately throws a security error, stopping the process cold. It’s a textbook example of secure coding: when a feature is too dangerous to exist, you don't tame it; you remove it entirely. The addition of comprehensive unit tests in util.test.ts to confirm this behavior is the cherry on top, ensuring this ghost won't rise from its grave in a future release.

Crafting the Perfect RCE Payload

So, how do we weaponize this? The attack path is terrifyingly simple. Our attacker, let's call her Eve, only needs one thing: the ability to create or edit a markdown file that the TinaCMS server will process. This could be a low-level content editor account, a compromised contractor's credentials, or even a system that ingests markdown from a shared folder.

Eve crafts her malicious blog post. The body of the post is irrelevant; the magic is all in the header. She uses the ---js delimiter to tell gray-matter to switch on its execution engine. The payload is a simple one-liner, disguised within a JSON object definition.

---js
{
  "title": "Pawned" + require("fs").readFileSync("/etc/passwd").toString()
}
---
# My Awesome Blog Post
 
This post is totally safe.

When Eve uploads this file, the TinaCMS backend dutifully picks it up. The gray-matter parser sees ---js, enters execution mode, and evaluates the object. To resolve the value for the title key, it must first execute require("fs").readFileSync("/etc/passwd").toString(). The contents of the server's password file are read into memory and appended to the title. While this PoC just logs the file, a real attacker would use child_process.execSync to get a reverse shell, giving them an interactive command prompt on the server.

Here is a simple visualization of the attack flow:

From Blog Post to Beachhead

Let's be clear about the impact. This isn't a cross-site scripting flaw or a denial of service. This is full, unauthenticated (from the server's perspective) Remote Code Execution. The attacker gains a foothold on your server with the same privileges as the Node.js process running TinaCMS. From there, the game is over.

The initial compromise is just the beginning. The attacker can read connection strings from environment variables, dump databases, and pivot to attack other internal services that trusted the now-compromised server. They can install crypto miners, deploy ransomware, or simply sit silently and exfiltrate sensitive company data over a period of months. All because a markdown parser had a feature that should never have existed.

The low EPSS score (0.08%) might suggest this is a low-risk vulnerability, but that metric predicts widespread, opportunistic exploitation. It says nothing about the risk of a targeted attack. For an attacker specifically targeting a company known to use TinaCMS, this vulnerability is a goldmine. The attack vector is subtle—who audits the content of markdown files for executable code?

Putting the Genie Back in the Bottle

The fix, thankfully, is straightforward: update your dependencies. If you're running TinaCMS, you need to move to tinacms >= 3.1.1, @tinacms/cli >= 2.0.4, and @tinacms/graphql >= 2.0.3. Running npm update or yarn upgrade should be your immediate priority. There is no complex migration path; it's a simple version bump to get the patched code.

The patch itself teaches a valuable lesson in supply chain security. You cannot blindly trust your dependencies, especially not their default configurations. The TinaCMS team did the right thing by explicitly disabling the dangerous engines in gray-matter, adopting a principle of least functionality. Any feature that isn't strictly necessary for your application's purpose is a potential attack surface.

Could this be bypassed? It's unlikely with the current fix, which is an explicit block. An attacker would have to find a vulnerability in one of the allowed engines (like the YAML or TOML parsers), which is a much harder task. However, it's a reminder to always treat user-supplied content, even from authenticated users, as fundamentally untrusted. The line between data and code can be dangerously thin.

For those who absolutely cannot update immediately, a temporary workaround would be to implement a pre-processing check. Your application could scan uploaded markdown files for the strings ---js, ---javascript, ---coffee, or ---coffeescript at the beginning of the file and reject them outright. It's a fragile, temporary band-aid, but it's better than leaving the front door unlocked.

Fix Analysis (1)

Technical Appendix

CVSS Score
7.3/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:P
EPSS Probability
0.08%
Top 76% most exploited

Affected Systems

TinaCMS@tinacms/cli@tinacms/graphql

Affected Versions Detail

ProductAffected VersionsFixed Version
tinacms
tinacms
< 3.1.13.1.1
@tinacms/cli
tinacms
< 2.0.42.0.4
@tinacms/graphql
tinacms
< 2.0.32.0.3
AttributeDetail
CWE IDCWE-94
WeaknessImproper Control of Generation of Code ('Code Injection')
Attack VectorNetwork
Attack ComplexityLow
Privileges RequiredLow
CVSS v4.0 Score7.3 (High)
EPSS Score0.08% (Low Probability)
Exploit StatusProof-of-Concept Available
CISA KEVNo

MITRE ATT&CK Mapping

MITRE ATT&CK Mapping

T1059.007Command and Scripting Interpreter: JavaScript
Execution
T1190Exploit Public-Facing Application
Initial Access
CWE-94
Improper Control of Generation of Code ('Code Injection')

The software constructs all or part of a code string using externally-controlled input, but it does not neutralize or incorrectly neutralizes the input from a code syntax perspective, which can lead to the injection of arbitrary code.

Exploit Resources

Known Exploits & Detection

Vulners (from GHSA)Provides a clear Proof-of-Concept demonstrating RCE by reading /etc/passwd via a crafted markdown file.

Vulnerability Timeline

Vulnerability Timeline

Fix is committed to the main branch.
2025-12-17
CVE-2025-68278 and GHSA-529f-9qwm-9628 are publicly disclosed.
2025-12-18
Proof-of-Concept becomes publicly available.
2025-12-18

References & Sources

  • [1]GitHub Advisory: Arbitrary Code Execution in tinacms
  • [2]Fix Commit
  • [3]NVD - CVE-2025-68278

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.