[object Object]

← back to Shopify Oauth Catcher

feat(server): 404-guard snapshot file paths

26ea6583e0bdeaa6ae7d0b02a5308fd1e3e1adde · 2026-05-19 21:23:55 -0700 · Steve Abrams

Adds Express middleware that rejects any request path matching common
editor/snapshot extensions (.bak, .bak.<x>, .pre-*, .orig, .rej, .swp,
trailing ~) with a 404 before reaching any route or static handler.

Defense-in-depth — if a future static dir is added or a stray snapshot
file is left in the deploy tree (or exposed via a misconfigured proxy),
it cannot leak source / config / token-shaped content over HTTP.

OAuth flow unchanged: /install and /callback handlers untouched.

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

Files touched

Diff

commit 26ea6583e0bdeaa6ae7d0b02a5308fd1e3e1adde
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue May 19 21:23:55 2026 -0700

    feat(server): 404-guard snapshot file paths
    
    Adds Express middleware that rejects any request path matching common
    editor/snapshot extensions (.bak, .bak.<x>, .pre-*, .orig, .rej, .swp,
    trailing ~) with a 404 before reaching any route or static handler.
    
    Defense-in-depth — if a future static dir is added or a stray snapshot
    file is left in the deploy tree (or exposed via a misconfigured proxy),
    it cannot leak source / config / token-shaped content over HTTP.
    
    OAuth flow unchanged: /install and /callback handlers untouched.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 server.js | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/server.js b/server.js
index bd85e3b..27b28fa 100644
--- a/server.js
+++ b/server.js
@@ -34,6 +34,15 @@ if (!CLIENT_ID || !CLIENT_SECRET) {
 }
 
 const app = express();
+
+// Defense-in-depth: 404 any request for editor/snapshot detritus before it
+// can reach a static handler or be served by a misconfigured proxy.
+const SNAPSHOT_RE = /\.(bak|orig|rej|swp)$|\.bak\.|\.pre-|~$/i;
+app.use((req, res, next) => {
+  if (SNAPSHOT_RE.test(req.path)) return res.status(404).send('not found');
+  next();
+});
+
 const states = new Map(); // state → {shop, ts}
 
 app.get('/install', (req, res) => {

← 8d63f76 chore(gitignore): broaden to ignore editor/snapshot detritus  ·  back to Shopify Oauth Catcher  ·  (newest)