[object Object]

← back to Stars of Design

Guard against serving .bak / .pre- snapshot artifacts from public/

e2ee6aa23a089fd92cca4267fb05bb7906151a4b · 2026-05-19 15:19:24 -0700 · Steve Abrams

Refactor passes across the DW fleet sometimes leave behind .bak /
.bak.<ts> / .pre-<label> snapshots next to the file they replace. If
one of those slips into public/ it ships to prod as a world-readable
static asset. Two-layer fix:

1. .gitignore — *.bak, *.bak.*, *.pre-* so new snapshots stop entering
   the tree to begin with.
2. server.js — small Express middleware in front of express.static()
   that 404s any URL path containing those patterns, so even an
   un-ignored slip can't be fetched. Uses 404 (not 403) so the
   existence of a snapshot can't be confirmed by path-probing.

No tracked .bak / .pre-* files exist in the repo today; this is a
forward-looking guard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit e2ee6aa23a089fd92cca4267fb05bb7906151a4b
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue May 19 15:19:24 2026 -0700

    Guard against serving .bak / .pre- snapshot artifacts from public/
    
    Refactor passes across the DW fleet sometimes leave behind .bak /
    .bak.<ts> / .pre-<label> snapshots next to the file they replace. If
    one of those slips into public/ it ships to prod as a world-readable
    static asset. Two-layer fix:
    
    1. .gitignore — *.bak, *.bak.*, *.pre-* so new snapshots stop entering
       the tree to begin with.
    2. server.js — small Express middleware in front of express.static()
       that 404s any URL path containing those patterns, so even an
       un-ignored slip can't be fetched. Uses 404 (not 403) so the
       existence of a snapshot can't be confirmed by path-probing.
    
    No tracked .bak / .pre-* files exist in the repo today; this is a
    forward-looking guard.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 .gitignore |  7 +++++++
 server.js  | 12 ++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/.gitignore b/.gitignore
index 4a0b3ea..b890d81 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,10 @@ tmp/
 dist/
 build/
 .next/
+
+# Snapshot/rollback artifacts from refactor passes — must never ship to prod.
+# Pair this with the static-bak guard middleware in server.js that 404s any
+# request whose path includes these patterns even if a file slips through.
+*.bak
+*.bak.*
+*.pre-*
diff --git a/server.js b/server.js
index a474c9f..bf1babc 100644
--- a/server.js
+++ b/server.js
@@ -66,6 +66,18 @@ app.use(express.json({ limit: '256kb' }));
 app.use(express.urlencoded({ extended: true, limit: '256kb' }));
 app.use(cookieParser());
 
+// Static-bak guard — refuse to serve any URL path that looks like a snapshot
+// or rollback artifact (foo.html.bak, foo.pre-refactor.js, etc.) even if
+// someone accidentally leaves one in public/. Pair with the .gitignore rules
+// for *.bak / *.bak.* / *.pre-*. Returns 404 (not 403) so an attacker can't
+// confirm a snapshot exists by path-probing.
+app.use((req, res, next) => {
+  if (/\.bak(?:\.|$)|\.pre-/.test(req.path)) {
+    return res.status(404).render('public/404', { title: 'Not found — Stars of Design' });
+  }
+  next();
+});
+
 app.use(express.static(path.join(__dirname, 'public'), {
   maxAge: '1h',
   setHeaders(res, p) {

← a7ac2a9 Add noreferrer to all rel=nofollow noopener external links  ·  back to Stars of Design  ·  Static-bak guard returns plain text, not EJS template 8fc1daa →