[object Object]

← back to Wallco Ai

SECURITY: SQL-escape interpolated paths/category in elements_extract_prod.py + pil-mural-composite.py (claude-codex finding #8)

b3db6de8ce57293d39b62cbe820a0ee3618e8f38 · 2026-06-01 14:18:02 -0700 · Steve Abrams

Files touched

Diff

commit b3db6de8ce57293d39b62cbe820a0ee3618e8f38
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jun 1 14:18:02 2026 -0700

    SECURITY: SQL-escape interpolated paths/category in elements_extract_prod.py + pil-mural-composite.py (claude-codex finding #8)
---
 scripts/elements_extract_prod.py | 6 +++++-
 scripts/pil-mural-composite.py   | 5 ++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/scripts/elements_extract_prod.py b/scripts/elements_extract_prod.py
index cd19058..3f33acf 100644
--- a/scripts/elements_extract_prod.py
+++ b/scripts/elements_extract_prod.py
@@ -217,10 +217,14 @@ def persist_paths(results):
         'CREATE TEMP TABLE _elem_apply (id BIGINT PRIMARY KEY, motif TEXT NOT NULL, ref TEXT NOT NULL);',
     ]
     CHUNK = 400
+    # SQL-escape single quotes in interpolated paths (claude-codex finding): a path
+    # containing a `'` would break the INSERT / inject SQL. id is int()-coerced.
+    def _q(s):
+        return "'" + str(s).replace("'", "''") + "'"
     for i in range(0, len(successes), CHUNK):
         batch = successes[i:i + CHUNK]
         values = ','.join(
-            f"({r['id']}, '{r['motif_path']}', '{r['ref_path']}')"
+            f"({int(r['id'])}, {_q(r['motif_path'])}, {_q(r['ref_path'])})"
             for r in batch
         )
         sql_parts.append(f"INSERT INTO _elem_apply (id, motif, ref) VALUES {values};")
diff --git a/scripts/pil-mural-composite.py b/scripts/pil-mural-composite.py
index cb35646..f658964 100644
--- a/scripts/pil-mural-composite.py
+++ b/scripts/pil-mural-composite.py
@@ -139,9 +139,12 @@ def main():
     elif args.category:
         cats = [args.category]
     for cat in cats:
+        # SQL-escape the category (from --category CLI arg) — a stray quote would
+        # break the query / inject (claude-codex finding).
+        cat_esc = str(cat).replace("'", "''")
         rows = psql("SELECT id FROM all_designs WHERE category='%s' AND is_published=TRUE "
                     "AND local_path IS NOT NULL AND NOT EXISTS (SELECT 1 FROM wallco_rooms r "
-                    "WHERE r.design_id=all_designs.id AND r.image_path IS NOT NULL) ORDER BY id;" % cat)
+                    "WHERE r.design_id=all_designs.id AND r.image_path IS NOT NULL) ORDER BY id;" % cat_esc)
         ids += [int(x) for x in rows.splitlines() if x.strip()]
     ids = sorted(set(ids))
     if not ids:

← c2f49d0 SECURITY: fix reflected XSS in htmlHead (<head> now esc()'d  ·  back to Wallco Ai  ·  fix(generator): batch child timeout + orphan-run reaper + re 929ffc6 →