# Unvalidated file write and upload

User-controlled path, filename, or version written to disk without containment or type checks

_Area: Web infrastructure and server-side requests. Seen in 2 disclosed reports; one confirmed bounty: $5,000; latest 2026-02-05. Updated 2026-11-02._

## How it works
A write destination is treated as trusted when it is not. The code takes a value the user controls — a log file path, an upload filename, a package version — and hands it to a filesystem or package-manager call that resolves it wherever it points. The broken assumption is that the value names a location inside a safe directory, or that it is a plain version string. Neither is enforced, so the write lands outside the intended area or executes something the caller chose [E1](https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2019-12-gcp-5k-file-uploading-csrf-html.md)[E2](https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-cloudflare-pages-privesc-and-page-tampering.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-f632-vm87-2m2f.md).

## Where it shows up
- Upload endpoints that accept multipart bodies and write files into a user's home or working directory [E1](https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2019-12-gcp-5k-file-uploading-csrf-html.md)
- Log-path parameters (`log_file`, `on_disk.log_file`) with only an authentication check and no directory restriction [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-f632-vm87-2m2f.md)
- Version or tool parameters interpolated into `npm install pkg@{value}` or similar install specs [E2](https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-cloudflare-pages-privesc-and-page-tampering.md)
- Endpoints reachable on a second origin or hostname that skip the CSRF/auth header check the primary origin enforces [E1](https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2019-12-gcp-5k-file-uploading-csrf-html.md)
- Writable config files (e.g. `config/local.yaml`, `.bashrc`, `ld.so.preload`) that are parsed or executed on restart [E1](https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2019-12-gcp-5k-file-uploading-csrf-html.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-f632-vm87-2m2f.md)
- Internal proxies that validate paths for one namespace but not per-tenant ones [E2](https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-cloudflare-pages-privesc-and-page-tampering.md)

## How to review
The invariant: every write path must resolve, after canonicalization, inside an allowlisted directory, and every version/tool argument must match a strict version grammar, not a URL or path. Check that the resolved real path (following symlinks) stays under the intended root; that filenames are stripped of separators and quoting tricks; that log content cannot carry attacker newlines into a parsed file; and that the same auth/CSRF checks apply on every origin serving the endpoint. For install specs, confirm the value cannot be a tarball URL or file path [E2](https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-cloudflare-pages-privesc-and-page-tampering.md).

## How finders spotted it
- Noticed the same editor served on two origins and that one lacked the `X-XSRF-PROTECTED` header the other had; then fuzzed the multipart parser and found a single quoted field could carry both name and filename, expressible as an HTML form input [E1](https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2019-12-gcp-5k-file-uploading-csrf-html.md)
- Read build tool source, saw a user env var interpolated into `npm install wrangler@{version}`, then read npm's argument parser to learn versions can be tarball URLs [E2](https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-cloudflare-pages-privesc-and-page-tampering.md)
- Noticed `/logger` accepted an arbitrary `log_file` with only an auth check, then reasoned that log lines are attacker-influenced and a writable config dir plus a missing config file turns logged text into parsed YAML on restart [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-f632-vm87-2m2f.md)

## Variants seen
- CSRF-driven upload writing files into a victim VM, escalated via `.bashrc` [E1](https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2019-12-gcp-5k-file-uploading-csrf-html.md)
- Symlink in build output to read files, plus version-string injection to run as root [E2](https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-cloudflare-pages-privesc-and-page-tampering.md)
- Arbitrary log-file path append to a config file, escalated via `ld.so.preload` [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-f632-vm87-2m2f.md)

## Impact and severity
Each case chained a write into code execution or cross-tenant access: stored XSS and persistent execution on VM restart [E1](https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2019-12-gcp-5k-file-uploading-csrf-html.md); root in the build sandbox and traversal to all users' assets and Workers code [E2](https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-cloudflare-pages-privesc-and-page-tampering.md); privilege escalation to RCE after restart [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-f632-vm87-2m2f.md). Severity rises with what the written file is later parsed or executed by, and with how many tenants share the writable location [E2](https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-cloudflare-pages-privesc-and-page-tampering.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-f632-vm87-2m2f.md).

## Seen in real software
Open-source packages and projects, and products, where this pattern was found. If the target runs one, compare the version it runs with the fix.
- **qdrant (rust)** >= 1.9.3, < 1.15.6, fixed in 1.15.6: qdrant has arbitrary file write via `/logger` endpoint (CVE-2026-25628). Report: https://bugbountylibrary.com/r/ghsa%3AGHSA-f632-vm87-2m2f.md. Fix: https://github.com/qdrant/qdrant/commit/32b7fdfb7f542624ecd1f7c8d3e2b13c4e36a2c1

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2019-12-gcp-5k-file-uploading-csrf-html.md
- E2: https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-cloudflare-pages-privesc-and-page-tampering.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-f632-vm87-2m2f.md
