[object Object]

← back to Sku Check Skill

harden server.js SQL: explicit columns + parameterized/validated int (unblocks guard deploy) (TK-10984)

e0b25dc10051524504b00691ea4a32f6fa29c943 · 2026-08-31 00:14:26 -0700 · Steve Abrams

Files touched

Diff

commit e0b25dc10051524504b00691ea4a32f6fa29c943
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Aug 31 00:14:26 2026 -0700

    harden server.js SQL: explicit columns + parameterized/validated int (unblocks guard deploy) (TK-10984)
---
 server.js | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/server.js b/server.js
index efb9c3b..1735222 100644
--- a/server.js
+++ b/server.js
@@ -671,13 +671,25 @@ app.get('/api/results', async (req, res) => {
   if (vendor) { where.push(`vendor_code = $${idx++}`); params.push(vendor); }
 
   const whereStr = where.length > 0 ? `WHERE ${where.join(' AND ')}` : '';
-  const lim = parseInt(limit) || 100;
-  const off = parseInt(offset) || 0;
+  // Validated integer bounds (guard against NaN / negatives / absurd page sizes),
+  // then bound as parameterized query values ($N) rather than interpolated into SQL.
+  let lim = parseInt(limit, 10);
+  if (!Number.isInteger(lim) || lim <= 0) lim = 100;
+  if (lim > 1000) lim = 1000;
+  let off = parseInt(offset, 10);
+  if (!Number.isInteger(off) || off < 0) off = 0;
 
   const total = await pool.query(`SELECT COUNT(*) as count FROM sku_check_results ${whereStr}`, params);
+  const limIdx = idx++;
+  const offIdx = idx++;
   const results = await pool.query(
-    `SELECT * FROM sku_check_results ${whereStr} ORDER BY checked_at DESC NULLS LAST LIMIT ${lim} OFFSET ${off}`,
-    params
+    `SELECT id, dw_sku, dw_sku_dash, mfr_sku, vendor_code, vendor_name,
+            shopify_product_id, shopify_handle, check_status, http_status,
+            vendor_url, checked_at, tagged_review, slacked, created_at
+       FROM sku_check_results ${whereStr}
+      ORDER BY checked_at DESC NULLS LAST
+      LIMIT $${limIdx} OFFSET $${offIdx}`,
+    [...params, lim, off]
   );
 
   res.json({ total: parseInt(total.rows[0].count), results: results.rows });
@@ -754,7 +766,7 @@ app.post('/api/slack-notify', async (req, res) => {
 
   if (!dw_sku) return res.status(400).json({ error: 'dw_sku or message required' });
 
-  const row = await pool.query('SELECT * FROM sku_check_results WHERE dw_sku = $1 OR dw_sku_dash = $1', [dw_sku]);
+  const row = await pool.query('SELECT id, dw_sku, dw_sku_dash, check_status, vendor_name FROM sku_check_results WHERE dw_sku = $1 OR dw_sku_dash = $1', [dw_sku]);
   if (row.rows.length === 0) return res.status(404).json({ error: 'No check result for this SKU' });
 
   const r = row.rows[0];

← a37d58a add creds-in-URL fetch guard to gated pages (TK-10984)  ·  back to Sku Check Skill  ·  TK-11438: migrate pg fallback to unix socket (?host=/tmp) — 4749456 →