← back to Interiordesignershowroom
snapshot before deploy: in-tree security headers (nosniff/frame/referrer/permissions, drop x-powered-by) + don't leak raw error to /api/render client
c34917c82012da8026a0295f910e5c0fad99afce · 2026-08-03 11:13:46 -0700 · steve
Files touched
Diff
commit c34917c82012da8026a0295f910e5c0fad99afce
Author: steve <steve@designerwallcoverings.com>
Date: Mon Aug 3 11:13:46 2026 -0700
snapshot before deploy: in-tree security headers (nosniff/frame/referrer/permissions, drop x-powered-by) + don't leak raw error to /api/render client
---
server.js | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/server.js b/server.js
index ed80382..70da6cc 100644
--- a/server.js
+++ b/server.js
@@ -13,6 +13,20 @@ const COLS = require('./lib/cols');
const app = express();
const PORT = process.env.PORT || 9820;
+// Security headers on every response (no dependency). A strict Content-Security-Policy
+// is deliberately DEFERRED: the storefront still emits inline onerror/style handlers that
+// a CSP without 'unsafe-inline' would break — that's a separate refactor. These four are
+// non-breaking and close the obvious gaps (MIME sniffing, clickjacking, referrer leakage,
+// unused powerful features). Also stop advertising the framework.
+app.disable('x-powered-by');
+app.use((_req, res, next) => {
+ res.set('X-Content-Type-Options', 'nosniff');
+ res.set('X-Frame-Options', 'SAMEORIGIN');
+ res.set('Referrer-Policy', 'strict-origin-when-cross-origin');
+ res.set('Permissions-Policy', 'camera=(), microphone=(), geolocation=(), browsing-topics=()');
+ next();
+});
+
app.use(express.json({ limit: '256kb' }));
app.use('/css', express.static(path.join(__dirname, 'public/css')));
app.use('/js', express.static(path.join(__dirname, 'public/js')));
@@ -482,7 +496,7 @@ app.post('/api/render', async (req, res) => {
// return the products in the room so the right panel can show them (shoppable)
const roomProducts = products.map((p) => ({ id: p.id, title: p.title, image_url: p.image_url, price: p.price, sale_price: p.sale_price, advertiser: p.advertiser, brand: p.brand }));
res.json({ ...out, cost, hotspots: loc.hotspots, products: roomProducts });
- } catch (e) { console.error('[render]', e.message); res.status(500).json({ error: e.message }); }
+ } catch (e) { console.error('[render]', e.message); res.status(500).json({ error: 'Render failed. Please try again.' }); }
});
app.get('/build', (_req, res) => {
← 81d733e refine: shared fmtStamp (storefront+admin, NaN/future-safe),
·
back to Interiordesignershowroom
·
security: response headers + non-breaking CSP (frame-ancesto 1bd3992 →