diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-29 23:32:47 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-29 23:32:47 +0300 |
| commit | 504fbf825bc153c9744c191f903c517e6dcad0d4 (patch) | |
| tree | 1b7b3566c6a895b383e72f1003798c19f1669480 | |
| parent | 9f0ceb6971c85f1fac8255bf420367b08f7e4acf (diff) | |
fix: prevent path traversal in UploadMedia
| -rw-r--r-- | internal/service/media.go | 7 | ||||
| -rw-r--r-- | internal/service/media_test.go | 12 |
2 files changed, 19 insertions, 0 deletions
diff --git a/internal/service/media.go b/internal/service/media.go index bf1bae0..71ca27c 100644 --- a/internal/service/media.go +++ b/internal/service/media.go @@ -245,6 +245,10 @@ func (s *mediaService) RestoreMedia(ctx context.Context, mediaID, userID int64) } func (s *mediaService) uniqueFilename(dir, filename string) string { + filename = filepath.Base(filename) + if filename == "." || filename == ".." || filename == "" { + return "" + } ext := filepath.Ext(filename) base := strings.TrimSuffix(filename, ext) @@ -276,6 +280,9 @@ func (s *mediaService) UploadMedia(ctx context.Context, setID, userID int64, fil } path := s.uniqueFilename(dir, filename) + if !strings.HasPrefix(filepath.Clean(path), filepath.Clean(dir)+string(filepath.Separator)) { + return nil, errors.New("invalid filename") + } f, err := os.Create(path) if err != nil { return nil, fmt.Errorf("create file: %w", err) diff --git a/internal/service/media_test.go b/internal/service/media_test.go index 7193ef7..edf2e27 100644 --- a/internal/service/media_test.go +++ b/internal/service/media_test.go @@ -575,6 +575,18 @@ func TestMediaService_UploadMedia(t *testing.T) { setErr: errors.New("boom"), wantErr: true, }, + { + name: "path traversal sanitized", + setExists: true, + filename: "../../etc/passwd", + wantErr: false, + }, + { + name: "path traversal dotdot rejected", + setExists: true, + filename: "..", + wantErr: true, + }, } for _, tt := range tests { |
