From 7abe38da7bdbb8ea452fc37d864c5a884487fc14 Mon Sep 17 00:00:00 2001
From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Date: Wed, 1 Apr 2026 09:25:34 +0300
Subject: [PATCH 1/2] Reject non-numeric elements inside list coords

Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com>
---
 Tests/test_imagepath.py      | 29 +++++++++++++++++++++++++++++
 src/path.c                   | 15 ++++++++++++++-
 3 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/Tests/test_imagepath.py b/Tests/test_imagepath.py
index ad8acde4938..8d230eb564c 100644
--- a/Tests/test_imagepath.py
+++ b/Tests/test_imagepath.py
@@ -51,6 +51,7 @@ def test_path() -> None:
         [0.0, 1.0],
         ((0, 1),),
         [(0, 1)],
+        [[0, 1]],
         ((0.0, 1.0),),
         [(0.0, 1.0)],
         array.array("f", [0, 1]),
@@ -68,6 +69,34 @@ def test_path_constructors(
     assert list(p) == [(0.0, 1.0)]
 
 
+@pytest.mark.parametrize(
+    "coords, expected",
+    (
+        ([[0, 1], [2, 3]], [(0.0, 1.0), (2.0, 3.0)]),
+        ([[0.0, 1.0], [2.0, 3.0]], [(0.0, 1.0), (2.0, 3.0)]),
+    ),
+)
+def test_path_list_of_lists(
+    coords: list[list[float]], expected: list[tuple[float, float]]
+) -> None:
+    p = ImagePath.Path(coords)
+    assert list(p) == expected
+
+
+@pytest.mark.parametrize(
+    "coords, message",
+    (
+        ([[1, 2, 3]], "coordinate list must contain exactly 2 coordinates"),
+        ([[1]], "coordinate list must contain exactly 2 coordinates"),
+        ([[[1, 2], [3, 4]]], "coordinate list must contain numbers"),
+        ([["a", "b"]], "coordinate list must contain numbers"),
+    ),
+)
+def test_invalid_list_coords(coords: list[list[object]], message: str) -> None:
+    with pytest.raises(ValueError, match=message):
+        ImagePath.Path(coords)
+
+
 def test_invalid_path_constructors() -> None:
     # Arrange / Act
     with pytest.raises(ValueError, match="incorrect coordinate type"):
diff --git a/src/path.c b/src/path.c
index 38300547c60..b88346d5f8f 100644
--- a/src/path.c
+++ b/src/path.c
@@ -118,14 +118,27 @@ assign_item_to_array(double *xy, Py_ssize_t j, PyObject *op) {
     } else if (PyNumber_Check(op)) {
         xy[j++] = PyFloat_AsDouble(op);
     } else if (PyList_Check(op)) {
+        if (PyList_GET_SIZE(op) != 2) {
+            PyErr_SetString(
+                PyExc_ValueError, "coordinate list must contain exactly 2 coordinates"
+            );
+            return -1;
+        }
         for (int k = 0; k < 2; k++) {
             PyObject *op1 = PyList_GetItemRef(op, k);
             if (op1 == NULL) {
                 return -1;
             }
-            j = assign_item_to_array(xy, j, op1);
+            if (PyFloat_Check(op1) || PyLong_Check(op1) || PyNumber_Check(op1)) {
+                j = assign_item_to_array(xy, j, op1);
+            } else {
+                j = -1;
+            }
             Py_DECREF(op1);
             if (j == -1) {
+                PyErr_SetString(
+                    PyExc_ValueError, "coordinate list must contain numbers"
+                );
                 return -1;
             }
         }
