From 7a6b1c1ada3ba6ca2ca4ed70cf51f2f5f30d7b1e Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Tue, 15 Sep 2026 18:01:49 +0200 Subject: fix(notify): cover expiry cleanup and harden the image-removal guard Split the dismiss test so expiry is exercised on its own: Expire removes the image without deleting the inert entry, and nothing asserted it. removeImage now requires filepath.Dir(filepath.Clean(path)) to equal the image directory, so a path carrying .. cannot reach a sibling daemon file such as queue.json. The previous prefix test accepted it. Not exploitable until Task 4 populates Popup.Image from a client hint, which is exactly why the guard is fixed now. --- internal/notify/service.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'internal/notify/service.go') diff --git a/internal/notify/service.go b/internal/notify/service.go index d46293f..2442127 100644 --- a/internal/notify/service.go +++ b/internal/notify/service.go @@ -14,7 +14,7 @@ package notify import ( "log" "os" - "strings" + "path/filepath" "sync" "time" @@ -52,12 +52,13 @@ func NewService(conn *dbus.Conn, dir string) *Service { } // removeImage unlinks only what the daemon wrote, so a client's own image-path -// is never touched. +// is never touched. A cleaned path must sit directly inside the image +// directory, which also refuses a `..` traversal to a sibling daemon file. func (s *Service) removeImage(path string) { if path == "" { return } - if !strings.HasPrefix(path, ImagesDir(s.dir)+string(os.PathSeparator)) { + if filepath.Dir(filepath.Clean(path)) != ImagesDir(s.dir) { return } os.Remove(path) -- cgit v1.2.3