diff --git a/crates/ui-egui/src/panels/image_trace.rs b/crates/ui-egui/src/panels/image_trace.rs
--- a/crates/ui-egui/src/panels/image_trace.rs
+++ b/crates/ui-egui/src/panels/image_trace.rs
@@ -29,7 +29,7 @@ fn ignore_color(params: &Value) -> [u8; 3] {
     let hex = params["ignoreColor"].as_str().unwrap_or("").trim_start_matches('#');
     let channel = |i: usize| hex.get(i * 2..i * 2 + 2).and_then(|h| u8::from_str_radix(h, 16).ok());
     match (hex.len(), channel(0), channel(1), channel(2)) {
-        (6, Some(r), Some(g), Some(b)) => [r, g, b],
+        (6, Some(r), Some(g), Some(b)) if hex.bytes().all(|b| b.is_ascii_hexdigit()) => [r, g, b],
         _ => [255; 3],
     }
 }
diff --git a/crates/ui-egui/src/panels/image_trace/tests.rs b/crates/ui-egui/src/panels/image_trace/tests.rs
--- a/crates/ui-egui/src/panels/image_trace/tests.rs
+++ b/crates/ui-egui/src/panels/image_trace/tests.rs
@@ -782,3 +782,10 @@ fn panel_and_menu_draw_headless() {
         out.textures_delta.clear();
     }
 }
+
+#[test]
+fn ignore_color_rejects_signs_in_hex() {
+    assert_eq!(ignore_color(&json!({"ignoreColor": "#+f+f+f"})), [255; 3]);
+    assert_eq!(ignore_color(&json!({"ignoreColor": "+0+0+0"})), [255; 3]);
+    assert_eq!(ignore_color(&json!({"ignoreColor": "#ff00ff"})), [255, 0, 255]);
+}
