VYPR
High severityOSV Advisory· Published Dec 12, 2025· Updated Dec 12, 2025

CVE-2025-67819

CVE-2025-67819

Description

An issue was discovered in Weaviate OSS before 1.33.4. Due to a lack of validation of the fileName field in the transfer logic, an attacker who can call the GetFile method while a shard is in the "Pause file activity" state and the FileReplicationService is reachable can read arbitrary files accessible to the service process.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A path traversal in Weaviate's shard movement API (GetFile method) lets an attacker read arbitrary files by manipulating the fileName field.

Vulnerability

CVE-2025-67819 is a medium-severity path traversal vulnerability in Weaviate OSS, an open-source vector database. The flaw resides in the shard movement API's transfer logic, where the fileName field is not validated. An attacker who can call the GetFile method while a shard is in the "Pause file activity" state can supply a malicious fileName containing parent-directory traversal sequences (e.g., ../../..) or absolute paths, escaping the intended shard root directory [1][2][4].

Exploitation

Exploitation requires the attacker to have the ability to call the GetFile method, and the FileReplicationService must be reachable. Additionally, the shard must be in the "Pause file activity" state. The Shard Movement API is disabled by default, which reduces the attack surface for most deployments [4]. The vulnerability was introduced in Weaviate version 1.30.0 [4].

Impact

A successful attacker can read arbitrary files accessible to the Weaviate service process, potentially exposing sensitive configuration files, credentials, or other data stored on the server's filesystem [2].

Mitigation

Weaviate has released security patches for versions 1.30.x, 1.31.x, 1.32.x, and 1.33.x. Users are advised to update to the latest patched versions (e.g., 1.33.4 or later). Weaviate Cloud and Marketplace customers have been patched automatically [4].

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/weaviate/weaviateGo
>= 1.30.0, < 1.30.201.30.20
github.com/weaviate/weaviateGo
>= 1.31.0-rc.0, < 1.31.191.31.19
github.com/weaviate/weaviateGo
>= 1.32.0-rc.0, < 1.32.161.32.16
github.com/weaviate/weaviateGo
>= 1.33.0-rc.0, < 1.33.41.33.4

Affected products

2

Patches

3
89c2270869e6

Fix path breakout in backup

https://github.com/weaviate/weaviateDirk KulawiakOct 31, 2025via ghsa
4 files changed · +80 6
  • entities/diskio/files.go+33 1 modified
    @@ -11,7 +11,12 @@
     
     package diskio
     
    -import "os"
    +import (
    +	"fmt"
    +	"os"
    +	"path/filepath"
    +	"strings"
    +)
     
     func FileExists(file string) (bool, error) {
     	_, err := os.Stat(file)
    @@ -33,3 +38,30 @@ func Fsync(path string) error {
     
     	return f.Sync()
     }
    +
    +// SanitizeFilePathJoin joins a root path and a relative file path, ensuring that the resulting path is within the root
    +// path. It assumes that the relativeFilePath is attacker controlled.
    +func SanitizeFilePathJoin(rootPath string, relativeFilePath string) (string, error) {
    +	// Resolve symlinks in root path
    +	rootPath, err := filepath.EvalSymlinks(rootPath)
    +	if err != nil {
    +		return "", fmt.Errorf("resolve symlinks for root path %q: %w", rootPath, err)
    +	}
    +
    +	// clean the path to remove any ../ or ./ sequences
    +	cleanFilePath := filepath.Clean(relativeFilePath)
    +	if filepath.IsAbs(cleanFilePath) {
    +		return "", fmt.Errorf("relative file path %q is an absolute path", relativeFilePath)
    +	}
    +	combinedPath := filepath.Join(rootPath, cleanFilePath)
    +	finalPath := filepath.Clean(combinedPath)
    +
    +	rel, err := filepath.Rel(rootPath, finalPath)
    +	if err != nil {
    +		return "", fmt.Errorf("make %q relative to %q: %w", finalPath, rootPath, err)
    +	}
    +	if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
    +		return "", fmt.Errorf("file path %q is outside shard root %q", finalPath, rootPath)
    +	}
    +	return finalPath, nil
    +}
    
  • entities/diskio/files_test.go+38 0 added
    @@ -0,0 +1,38 @@
    +package diskio
    +
    +import (
    +	"path/filepath"
    +	"testing"
    +
    +	"github.com/stretchr/testify/require"
    +)
    +
    +func TestSanitizeFilePathJoin(t *testing.T) {
    +	tests := []struct {
    +		name     string
    +		relative string
    +		wantErr  bool
    +	}{
    +		{name: "valid relative", relative: "sub/file.txt", wantErr: false},
    +		{name: "escape with dot-dot", relative: filepath.Join("..", "outside", "out.txt"), wantErr: true},
    +		{name: "absolute path rejected", relative: filepath.Join(string(filepath.Separator), "etc", "passwd"), wantErr: true},
    +		{name: "normalized traversal inside root", relative: filepath.Join("sub", "..", "sub", "file.txt"), wantErr: false},
    +	}
    +
    +	for _, tc := range tests {
    +		t.Run(tc.name, func(t *testing.T) {
    +			root := t.TempDir()
    +			got, err := SanitizeFilePathJoin(root, tc.relative)
    +
    +			if tc.wantErr {
    +				require.Error(t, err)
    +				return
    +			}
    +			require.NoError(t, err)
    +			rootPath, err := filepath.EvalSymlinks(root)
    +			require.NoError(t, err)
    +
    +			require.Equal(t, filepath.Join(rootPath, "sub", "file.txt"), got)
    +		})
    +	}
    +}
    
  • usecases/backup/zip.go+8 4 modified
    @@ -26,6 +26,7 @@ import (
     	"time"
     
     	"github.com/weaviate/weaviate/entities/backup"
    +	"github.com/weaviate/weaviate/entities/diskio"
     )
     
     // CompressionLevel represents supported compression level
    @@ -101,7 +102,7 @@ func (z *zip) WriteShard(ctx context.Context, sd *backup.ShardDescriptor) (writt
     	n, err = z.WriteRegulars(ctx, sd.Files)
     	written += n
     
    -	return
    +	return written, err
     }
     
     func (z *zip) WriteRegulars(ctx context.Context, relPaths []string) (written int64, err error) {
    @@ -170,7 +171,7 @@ func (z *zip) writeOne(ctx context.Context, info fs.FileInfo, relPath string, r
     		}
     		return written, fmt.Errorf("copy: %s %w", relPath, err)
     	}
    -	return
    +	return written, err
     }
     
     // lastWritten number of bytes
    @@ -239,7 +240,10 @@ func (u *unzip) ReadChunk() (written int64, err error) {
     		}
     
     		// target file
    -		target := filepath.Join(u.destPath, header.Name)
    +		target, err := diskio.SanitizeFilePathJoin(u.destPath, header.Name)
    +		if err != nil {
    +			return written, fmt.Errorf("sanitize file path %s: %w", header.Name, err)
    +		}
     		switch header.Typeflag {
     		case tar.TypeDir:
     			if err := os.MkdirAll(target, 0o755); err != nil {
    @@ -295,7 +299,7 @@ type readCloser struct {
     func (r *readCloser) Read(p []byte) (n int, err error) {
     	n, err = r.src.Read(p)
     	atomic.AddInt64(&r.n, int64(n))
    -	return
    +	return n, err
     }
     
     func (r *readCloser) Close() error { return r.src.Close() }
    
  • usecases/backup/zip_test.go+1 1 modified
    @@ -138,7 +138,7 @@ func TestUnzipPathEscape(t *testing.T) {
     	}()
     
     	_, err = uz.ReadChunk()
    -	require.NoError(t, err)
    +	require.ErrorContains(t, err, "outside shard root")
     
     	entries, err := os.ReadDir(completelyUnrelatedDir)
     	require.NoError(t, err)
    
4ff2cc89277c

Return correct path

https://github.com/weaviate/weaviateDirk KulawiakOct 30, 2025via ghsa
1 file changed · +11 5
  • adapters/repos/db/shard_backup.go+11 5 modified
    @@ -324,16 +324,22 @@ func (s *Shard) sanitizeFilePath(relativeFilePath string) (string, error) {
     	combinedPath := filepath.Join(s.index.Config.RootPath, cleanFilePath)
     	finalPath, err := filepath.EvalSymlinks(combinedPath)
     	if err != nil {
    -		return "", fmt.Errorf("resolve symlinks for %q: %w", combinedPath, err)
    +		return "", fmt.Errorf("resolve symlinks for %q: %w", finalPath, err)
     	}
     	finalPath = filepath.Clean(finalPath)
     
    -	rel, err := filepath.Rel(s.index.Config.RootPath, finalPath)
    +	// Resolve symlinks in root path - this is important for testing on MacOs where /var is a symlink
    +	rootPath, err := filepath.EvalSymlinks(s.index.Config.RootPath)
     	if err != nil {
    -		return "", fmt.Errorf("make %q relative to %q: %w", combinedPath, s.index.Config.RootPath, err)
    +		return "", fmt.Errorf("resolve symlinks for root path %q: %w", s.index.Config.RootPath, err)
    +	}
    +
    +	rel, err := filepath.Rel(rootPath, finalPath)
    +	if err != nil {
    +		return "", fmt.Errorf("make %q relative to %q: %w", finalPath, rootPath, err)
     	}
     	if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
    -		return "", fmt.Errorf("file path %q is outside shard root %q", relativeFilePath, s.index.Config.RootPath)
    +		return "", fmt.Errorf("file path %q is outside shard root %q", finalPath, rootPath)
     	}
    -	return combinedPath, nil
    +	return finalPath, nil
     }
    
b18cc7ea82d8

Fix path sanitazion and adapt test

https://github.com/weaviate/weaviateDirk KulawiakOct 30, 2025via ghsa
2 files changed · +34 9
  • adapters/repos/db/shard_backup.go+26 2 modified
    @@ -17,6 +17,7 @@ import (
     	"io"
     	"os"
     	"path/filepath"
    +	"strings"
     	"time"
     
     	"github.com/weaviate/weaviate/entities/backup"
    @@ -283,7 +284,10 @@ func (s *Shard) GetFileMetadata(ctx context.Context, relativeFilePath string) (f
     
     	s.mayResetInactivityTimer()
     
    -	finalPath := filepath.Join(s.Index().Config.RootPath, relativeFilePath)
    +	finalPath, err := s.sanitizeFilePath(relativeFilePath)
    +	if err != nil {
    +		return file.FileMetadata{}, fmt.Errorf("sanitize file path %q: %w", relativeFilePath, err)
    +	}
     	return file.GetFileMetadata(finalPath)
     }
     
    @@ -298,7 +302,10 @@ func (s *Shard) GetFile(ctx context.Context, relativeFilePath string) (io.ReadCl
     
     	s.mayResetInactivityTimer()
     
    -	finalPath := filepath.Join(s.Index().Config.RootPath, relativeFilePath)
    +	finalPath, err := s.sanitizeFilePath(relativeFilePath)
    +	if err != nil {
    +		return nil, fmt.Errorf("sanitize file path %q: %w", relativeFilePath, err)
    +	}
     
     	reader, err := os.Open(finalPath)
     	if err != nil {
    @@ -307,3 +314,20 @@ func (s *Shard) GetFile(ctx context.Context, relativeFilePath string) (io.ReadCl
     
     	return reader, nil
     }
    +
    +func (s *Shard) sanitizeFilePath(relativeFilePath string) (string, error) {
    +	// clean the path to remove any ../ or ./ sequences
    +	cleanFilePath := filepath.Clean(relativeFilePath)
    +	if filepath.IsAbs(cleanFilePath) {
    +		return "", fmt.Errorf("relative file path %q is an absolute path", relativeFilePath)
    +	}
    +	final := filepath.Join(s.index.Config.RootPath, cleanFilePath)
    +	rel, err := filepath.Rel(s.index.Config.RootPath, final)
    +	if err != nil {
    +		return "", fmt.Errorf("make %q relative to %q: %w", final, s.index.Config.RootPath, err)
    +	}
    +	if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
    +		return "", fmt.Errorf("file path %q is outside shard root %q", relativeFilePath, s.index.Config.RootPath)
    +	}
    +	return final, nil
    +}
    
  • adapters/repos/db/shard_path_test.go+8 7 modified
    @@ -1,14 +1,14 @@
     package db
     
     import (
    -	"fmt"
     	"os"
     	"path/filepath"
     	"testing"
     	"time"
     
     	"github.com/stretchr/testify/require"
     	"github.com/weaviate/weaviate/entities/additional"
    +	"github.com/weaviate/weaviate/entities/backup"
     )
     
     func TestShardFileSanitize(t *testing.T) {
    @@ -19,8 +19,6 @@ func TestShardFileSanitize(t *testing.T) {
     	ctx := testCtx()
     	className := "TestClass"
     	shd, _ := testShard(t, ctx, className)
    -	rootPath := shd.Index().Config.RootPath
    -	fmt.Println(rootPath)
     	require.NoError(t, shd.HaltForTransfer(ctx, false, 100*time.Millisecond))
     	amount := 10
     
    @@ -35,10 +33,13 @@ func TestShardFileSanitize(t *testing.T) {
     	require.Nil(t, err)
     	require.Equal(t, amount, len(objs))
     
    -	file, err := shd.GetFile(ctx, "../001/secret.txt")
    -	require.NoError(t, err)
    +	_, err = shd.GetFile(ctx, "../001/secret.txt")
    +	require.Error(t, err)
    +
    +	ret := &backup.ShardDescriptor{}
    +	require.NoError(t, shd.ListBackupFiles(ctx, ret))
     
    -	buf := make([]byte, 6)
    -	_, err = file.Read(buf)
    +	file, err := shd.GetFile(ctx, ret.ShardVersionPath)
     	require.NoError(t, err)
    +	require.NotNil(t, file)
     }
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.