# Saltcorn has an Unauthenticated Path Traversal in sync endpoints, allowing arbitrary file write and directory read

Unauthenticated path traversal in Saltcorn sync endpoints lets attackers write changes.json anywhere and list/read arbitrary directories.

- Payout: Research
- Severity: high
- Program: Saltcorn
- Found by: axel-corsiez
- Disclosed: 2026-04-10
- CVE: CVE-2026-40163
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-32pv-mpqg-h292
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-32pv-mpqg-h292
- Tags: area:web domain:web impact:data-leak impact:integrity impact:rce kind:research platform:ghsa sev:high tech:nodejs technique:incomplete-fix vuln:file-upload vuln:info-disclosure vuln:path-traversal

**Target:** Node.js web server mobile sync endpoints (/sync/offline_changes, /sync/upload_finished)
**Root cause:** newSyncTimestamp and dir_name request parameters are passed unsanitized into path.join(), which normalizes ../ sequences and escapes the sync base directory; the existing File.normalise_in_base() helper was not applied to these routes.
**Steps:**
1. POST to `/sync/offline_changes` with body `{"newSyncTimestamp": "../../../../tmp/saltcorn_poc", "oldSyncTimestamp": "0", "changes": {"proof": "path_traversal_write"}}`
2. Server joins rootFolder/mobile_app/sync with `../../../../tmp/saltcorn_poc_public`, mkdir -p, writes changes.json with attacker JSON
3. GET `/sync/upload_finished?dir_name=../../../../etc` to list arbitrary directory contents
4. Read translated-ids.json, unique-conflicts.json, data-conflicts.json or error.json from any directory
**How found:** Reporter noticed the same file's clean_sync_dir endpoint correctly used File.normalise_in_base() (from prior fix GHSA-43f3-h63w-p6f6) while sibling endpoints offline_changes and upload_finished passed params straight to path.join() with no auth middleware.
**Exploitation:** Unauthenticated attacker sends crafted JSON body or query param; path.join normalization escapes the sync dir, yielding arbitrary directory creation, arbitrary changes.json write, and directory listing/JSON read. RCE possible by writing to cron/systemd/Node module paths.
**Escalation:** Writing changes.json to sensitive paths (cron, systemd, Node.js module paths) could yield remote code execution.
**Insight:** When a codebase has a path-safety helper added by a prior advisory, grep every other path.join() call in the same file/module for the same sink — incomplete fixes leave sibling endpoints vulnerable.

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

**curl POST writing arbitrary changes.json via traversal**

```
curl -X POST http://TARGET:3000/sync/offline_changes \
  -H "Content-Type: application/json" \
  -d '{
    "newSyncTimestamp": "../../../../tmp/saltcorn_poc",
    "oldSyncTimestamp": "0",
    "changes": {"proof": "path_traversal_write"}
  }'
```

**curl GET listing /etc via dir_name traversal**

```
curl "http://TARGET:3000/sync/upload_finished?dir_name=../../../../etc"
```

