···34783478// isMimeMismatch returns true if the file extension claims to be a safe type
34793479// but magic-byte detection says otherwise (e.g. a script disguised as .png).
34803480func isMimeMismatch(ext, detected string) bool {
34813481+ // SVG is XML-based, so DetectContentType returns text/xml, text/plain, or
34823482+ // text/html — all valid for real SVGs. Only flag binary content as suspicious.
34833483+ if ext == ".svg" {
34843484+ return !strings.HasPrefix(detected, "text/") && !strings.HasPrefix(detected, "image/")
34853485+ }
34813486 expected, ok := expectedMimePrefix[ext]
34823487 if !ok {
34833488 return false // unknown extension — can't validate, let it through
+8
internal/ui/model_test.go
···641641 {"real mp3", ".mp3", "audio/mpeg", false},
642642 {"real mp4", ".mp4", "video/mp4", false},
643643644644+ // SVG — XML/text-based types are valid, binary is suspicious
645645+ {"real svg as text/xml", ".svg", "text/xml; charset=utf-8", false},
646646+ {"real svg as text/plain", ".svg", "text/plain; charset=utf-8", false},
647647+ {"real svg as text/html", ".svg", "text/html; charset=utf-8", false},
648648+ {"real svg as image/svg+xml", ".svg", "image/svg+xml", false},
649649+ {"binary disguised as svg", ".svg", "application/octet-stream", true},
650650+ {"zip disguised as svg", ".svg", "application/zip", true},
651651+644652 // Unknown extensions — can't validate, should pass through
645653 {"unknown ext .xyz", ".xyz", "text/plain; charset=utf-8", false},
646654 {"unknown ext .foo", ".foo", "application/octet-stream", false},