# @tinacms/graphql has Path Traversal that leads to overwrite of arbitrary files

Unauthenticated GraphQL updateDocument mutation in @tinacms/graphql accepts backslash traversal in relativePath, letting attackers overwrite arbitrary project files like package.json.

- Payout: Research
- Severity: high
- Program: TinaCMS
- Found by: aarjubh
- Disclosed: 2026-03-30
- CVE: CVE-2026-33949
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-v9p7-gf3q-h779
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-v9p7-gf3q-h779
- Tags: area:oss domain:oss impact:integrity impact:rce kind:research platform:ghsa sev:high tech:graphql tech:nodejs technique:source-review vuln:path-traversal

**Target:** GraphQL updateDocument mutation / filesystem bridge
**Root cause:** getValidatedPath's regex-based check treats only forward slashes as separators, so backslash sequences like `x\..\..\..\package.json` pass validation but are normalized as traversal by fs/path utilities on Mac/Linux.
**Steps:**
1. Start the TinaCMS dev server (GraphQL at http://localhost:4001/graphql).
2. Send `curl -X POST http://localhost:4001/graphql -H "Content-Type: application/json" -d '{"query": "mutation { updateDocument(collection: \"global\", relativePath: \"x\\\\..\\\\..\\\\..\\\\package.json\", params: { global: { header: { name: \"OVERWRITTEN\" } } }) { __typename } }"}'`.
3. Observe root package.json replaced with the supplied payload.
**How found:** Reporter inspected getValidatedPath and assertWithinBase in the filesystem bridge and noticed the regex only accounts for forward slashes, hypothesizing backslashes would bypass validation while still being treated as separators by fs/path normalization on non-Windows platforms.
**Exploitation:** Unauthenticated attacker with network access to the GraphQL API submits updateDocument with a backslash traversal relativePath, causing the filesystem bridge to write attacker-controlled content outside the content directory — overwriting package.json/tsconfig.json, planting scripts in public/, or modifying build/server files for code execution.
**Escalation:** Overwrite build scripts or server-side logic files that are later executed, converting arbitrary file write into arbitrary code execution.
**Insight:** When auditing path-containment checks, test separator mismatches: a validator that only strips `/` can be bypassed with `\` on POSIX where path.normalize/fs still resolve it as traversal — check every place the validated string is re-parsed.

## Proof of concept (copied exactly from the original report)

**curl GraphQL mutation with backslash path traversal**

```
curl -X POST http://localhost:4001/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "mutation { updateDocument(collection: \"global\", relativePath: \"x\\\\..\\\\..\\\\..\\\\package.json\", params: { global: { header: { name: \"OVERWRITTEN\" } } }) { __typename } }"}
```

