Severity by source
AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:L
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:L
Lifecycle Timeline
4Blast Radius
ecosystem impact- 6 npm packages depend on @tinacms/graphql (3 direct, 3 indirect)
Ecosystem-wide dependent count for version 2.2.2.
DescriptionGitHub Advisory
Summary
@tinacms/cli recently added lexical path-traversal checks to the dev media routes, but the implementation still validates only the path string and does not resolve symlink or junction targets.
If a link already exists under the media root, Tina accepts a path like pivot/written-from-media.txt as "inside" the media directory and then performs real filesystem operations through that link target. This allows out-of-root media listing and write access, and the same root cause also affects delete.
Details
The dev media handlers validate user-controlled paths with:
function resolveWithinBase(userPath: string, baseDir: string): string {
const resolvedBase = path.resolve(baseDir);
const resolved = path.resolve(path.join(baseDir, userPath));
if (resolved === resolvedBase) {
return resolvedBase;
}
if (resolved.startsWith(resolvedBase + path.sep)) {
return resolved;
}
throw new PathTraversalError(userPath);
}
function resolveStrictlyWithinBase(userPath: string, baseDir: string): string {
const resolvedBase = path.resolve(baseDir) + path.sep;
const resolved = path.resolve(path.join(baseDir, userPath));
if (!resolved.startsWith(resolvedBase)) {
throw new PathTraversalError(userPath);
}
return resolved;
}But the validated path is then used directly for real filesystem access:
filesStr = await fs.readdir(validatedPath);
...
await fs.ensureDir(path.dirname(saveTo));
file.pipe(fs.createWriteStream(saveTo));
...
await fs.remove(file);This does not account for symlinks/junctions already present below the media root. A path such as pivot/secret.txt can be lexically inside the media directory while the filesystem target is outside it.
Local Reproduction
I verified this locally with a real junction on Windows.
Test layout:
- media root:
D:\bugcrowd\tinacms\temp\junction-repro4\public\uploads - junction under media root:
public\uploads\pivot -> D:\bugcrowd\tinacms\temp\junction-repro4\outside - file outside the media root:
outside\secret.txt
Tina's current media-path validation logic was applied and used to perform the same list/write operations the route handlers use.
Observed result:
{
"media": {
"base": "D:\\bugcrowd\\tinacms\\temp\\junction-repro4\\public\\uploads",
"resolvedListPath": "D:\\bugcrowd\\tinacms\\temp\\junction-repro4\\public\\uploads\\pivot",
"listedEntries": [
"secret.txt"
],
"resolvedWritePath": "D:\\bugcrowd\\tinacms\\temp\\junction-repro4\\public\\uploads\\pivot\\written-from-media.txt",
"outsideWriteExists": true,
"outsideWriteContents": "MEDIA_ESCAPE"
}
}This shows the problem clearly:
- the path validator accepted
pivot - listing revealed a file from outside the media root
- writing to
pivot/written-from-media.txtcreatedoutside\written-from-media.txt
The delete path uses the same flawed containment model and should be hardened at the same time.
Impact
- Out-of-root file listing via
/media/list/... - Out-of-root file write via
/media/upload/... - Likely out-of-root file delete via
/media/...DELETE, using the same path-validation gap - Bypass of the recent path traversal hardening for any deployment whose media tree contains a link to another location
This is especially relevant in development and self-hosted workflows where the media directory may contain symlinks or junctions intentionally or via repository content.
Recommended Fix
Harden media path validation with canonical filesystem checks:
- resolve the real base path with
fs.realpath() - resolve the real target path, or for writes the nearest existing parent
- compare canonical paths rather than lexical strings
- reject any operation that traverses through a symlink/junction to leave the real media root
path.resolve(...).startsWith(...) is not sufficient for filesystem security on linked paths.
Resources
packages/@tinacms/cli/src/next/commands/dev-command/server/media.tspackages/@tinacms/cli/src/server/models/media.tspackages/@tinacms/cli/src/utils/path.ts
AnalysisAI
TinaCMS CLI media handlers can be bypassed via symlink/junction traversal, allowing authenticated low-privilege attackers to list, write, and delete files outside the configured media root directory. The vulnerability exists in @tinacms/cli's dev server media routes despite recent path-traversal hardening, because validation performs only lexical string checks without resolving symlink targets. Attack complexity is high (requires pre-existing symlink under media root), but impact is significant with confirmed read/write primitives. Vendor patch available via GitHub commit f124eaba. EPSS and KEV data not provided; no public exploit identified at time of analysis beyond researcher's local Windows junction proof-of-concept.
Technical ContextAI
TinaCMS CLI (npm package @tinacms/cli) provides development server routes for media file management. The affected code in media.ts and path.ts implements path-traversal protection using path.resolve() with lexical string prefix matching (startsWith checks). This approach validates that user-supplied paths resolve to strings beginning with the media base directory but does not account for filesystem indirection via symbolic links or Windows junctions. CWE-22 (Improper Limitation of a Pathname to a Restricted Directory) occurs because the validated path is passed directly to Node.js fs operations (readdir, createWriteStream, remove) which follow symlinks by default. When a symlink exists under the media root pointing outside it, paths like 'pivot/file.txt' pass lexical validation but filesystem operations target the link destination. The vulnerability affects the /media/list, /media/upload, and DELETE /media endpoints in the dev server. Canonical path resolution with fs.realpath() is required to detect and block symlink-based directory escapes before filesystem operations occur.
RemediationAI
Vendor-released patch: GitHub commit f124eabaca10dac9a4d765c9e4135813c4830955 addresses the symlink traversal vulnerability by implementing canonical path resolution. Users should upgrade @tinacms/cli to the patched version specified in the advisory at https://github.com/tinacms/tinacms/security/advisories/GHSA-g87c-r2jp-293w. The fix replaces lexical string validation with fs.realpath() canonicalization to resolve symlink targets before performing containment checks, ensuring filesystem operations cannot escape the media root via indirection. Until patching is complete, immediate workarounds include auditing the media directory tree to identify and remove any symlinks or junctions, restricting filesystem write access to prevent symlink creation under the media root, and limiting dev server exposure to trusted networks only. For self-hosted production deployments, consider disabling dev server media routes entirely if not required. Review application logs for suspicious media route access patterns targeting paths with multiple directory components that could indicate reconnaissance or exploitation attempts. The delete endpoint uses identical validation logic and is addressed by the same patch.
The x86-64 kernel system-call functionality in Xen 4.1.2 and earlier, as used in Citrix XenServer 6.0.2 and earlier and
An authenticated path traversal vulnerability in Langflow's file upload functionality allows attackers to write arbitrar
Canonical snapd before version 2.37.1 incorrectly performed socket owner validation, allowing an attacker to run arbitra
An authorization bypass vulnerability in gRPC-Go allows attackers to circumvent path-based access control by sending HTT
Arbitrary file read in Langroid's SQLChatAgent (<= 0.63.0) lets an attacker who can influence the LLM-generated SQL exfi
An issue was discovered in the jsrsasign package through 8.0.18 for Node.js. Rated high severity (CVSS 7.5), this vulner
The Elliptic package 6.5.2 for Node.js allows ECDSA signature malleability via variations in encoding, leading '\0' byte
Resource exhaustion in OpenTelemetry Go propagation library (v1.41.0 and earlier) enables remote attackers to trigger se
A vulnerability in the seccomp filters of Canonical snapd before version 2.37.4 allows a strict mode snap to insert char
The Linux kernel before 3.15.4 on Intel processors does not properly restrict use of a non-canonical value for the saved
concrete5 8.1.0 places incorrect trust in the HTTP Host header during caching, if the administrator did not define a "ca
Timestamp forgery in sigstore-js allows an attacker supplying a crafted bundle v0.2 to manipulate certificate validity w
Same weakness CWE-22 – Path Traversal
View allSame technique Path Traversal
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-17964
GHSA-g87c-r2jp-293w