<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Amit Feldman</title>
    <description>The latest articles on DEV Community by Amit Feldman (@amitfeldman).</description>
    <link>https://dev.to/amitfeldman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4052001%2Fed8ff31d-1d15-45d3-87b2-e461dde0406d.png</url>
      <title>DEV Community: Amit Feldman</title>
      <link>https://dev.to/amitfeldman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amitfeldman"/>
    <language>en</language>
    <item>
      <title>All six security headers fixed in a day — the Macless before/after</title>
      <dc:creator>Amit Feldman</dc:creator>
      <pubDate>Sun, 16 Aug 2026 15:04:11 +0000</pubDate>
      <link>https://dev.to/amitfeldman/all-six-security-headers-fixed-in-a-day-the-macless-beforeafter-5343</link>
      <guid>https://dev.to/amitfeldman/all-six-security-headers-fixed-in-a-day-the-macless-beforeafter-5343</guid>
      <description>&lt;p&gt;Earlier today I left a findings-first comment on a launch writeup here: a passive scan of the product's site, the top findings with the concrete fix, and an offer of a free re-scan once deployed. No pitch — the scan is the conversation.&lt;/p&gt;

&lt;p&gt;The maker read it, put Cloudflare in front of his GitHub Pages site, and closed every single finding within hours. This is the before/after.&lt;/p&gt;

&lt;h2&gt;
  
  
  The launch
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/maclessdev/how-to-build-and-ship-an-ios-app-without-a-mac-17o5"&gt;Macless&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/maclessdev"&gt;@maclessdev&lt;/a&gt; — a GitHub-Actions pipeline, signing scripts, and notes for building and submitting an iOS app to the App Store without owning a Mac. The marketing page lives at macless.dev, hosted on GitHub Pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before (scan, Aug 16): 10 passed / 4 warnings / 2 failures
&lt;/h2&gt;

&lt;p&gt;The base was decent: TLS clean (Let's Encrypt, TLSv1.3), fast response (266 ms), title, meta description, exactly one H1, robots.txt and sitemap.xml live.&lt;/p&gt;

&lt;p&gt;The gap was the entire security-header layer — all six missing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No HSTS&lt;/strong&gt; — every first visit over HTTP was downgrade-able&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Content-Security-Policy&lt;/strong&gt; — no XSS mitigation layer at all&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No X-Frame-Options&lt;/strong&gt; — clickjacking exposure&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No X-Content-Type-Options, Referrer-Policy, Permissions-Policy&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The frustrating part: none of this is application work. GitHub Pages doesn't let you set custom headers, full stop — so the fix isn't a code change, it's an architecture tweak.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: Cloudflare in front, two Transform Rules
&lt;/h2&gt;

&lt;p&gt;He put Cloudflare in front of the Pages site (free tier) and set the headers at the edge with Transform Rules — no deploy, no code, DNS plus config.&lt;/p&gt;

&lt;h2&gt;
  
  
  After (re-scan, same day — verified twice): 16 passed / 0 warnings / 0 failures
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HSTS&lt;/strong&gt;: &lt;code&gt;max-age=15552000&lt;/code&gt; (180 days)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSP&lt;/strong&gt;: &lt;code&gt;default-src 'self'; script-src 'none'; style-src 'self'; img-src 'self'; font-src 'self'; frame-ancestors 'none'; base-uri 'self'; object-src 'none'; form-action 'self'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;X-Frame-Options: DENY&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;X-Content-Type-Options: nosniff&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Referrer-Policy: strict-origin-when-cross-origin&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permissions-Policy&lt;/strong&gt;: geolocation, microphone, camera all locked down&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That CSP deserves a second look. &lt;code&gt;script-src 'none'&lt;/code&gt; is bolder than most production sites dare to run — it says this page executes zero JavaScript, which for a static marketing page is exactly true and exactly right. &lt;code&gt;frame-ancestors 'none'&lt;/code&gt; plus XFO DENY is belt-and-suspenders clickjacking defense. This isn't a header set copied from a blog post; it's a header set matched to what the page actually does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three takeaways for anyone launching on GitHub Pages
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Pages can't set headers — put a proxy in front.&lt;/strong&gt; GitHub Pages serves your files and nothing else. If your launch page lives there, the security-header layer doesn't exist until you add Cloudflare (or any CDN that can mutate response headers) in front of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The fix is a Transform Rule, not a sprint.&lt;/strong&gt; Cloudflare → Rules → Transform Rules → Modify Response Header. One rule can set every static header. Total elapsed work: minutes. The entire "after" column above required zero commits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Match CSP to reality, then tighten.&lt;/strong&gt; A static page can run &lt;code&gt;script-src 'none'&lt;/code&gt;. An app shell can't. Start from what the page genuinely loads, enforce that, and resist the urge to cargo-cult a permissive policy you saw elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm telling this story
&lt;/h2&gt;

&lt;p&gt;Because this is the loop that works: findings → fix → verified re-scan. &lt;a class="mentioned-user" href="https://dev.to/maclessdev"&gt;@maclessdev&lt;/a&gt; didn't pay anyone for this — the first scan and the re-scan were free, and his launch page now passes checks that show up verbatim in enterprise security questionnaires.&lt;/p&gt;

&lt;p&gt;I run these scans findings-first on launch posts here regardless of whether anyone buys anything. If you want the full deep pass — auth-flow edge cases, header drift across routes, perf budget, prioritized fix list with stack-specific snippets — that's the Launch-Ready Audit ($99, 48h turnaround): &lt;a href="https://afeldman2.gumroad.com/l/zxpluh?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=casestudy-macless" rel="noopener noreferrer"&gt;https://afeldman2.gumroad.com/l/zxpluh?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=casestudy-macless&lt;/a&gt;&lt;br&gt;
The Deep Dive ($149) adds a written remediation plan + re-scan verification: &lt;a href="https://afeldman2.gumroad.com/l/wmdfxb?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=casestudy-macless-deepdive" rel="noopener noreferrer"&gt;https://afeldman2.gumroad.com/l/wmdfxb?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=casestudy-macless-deepdive&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if I commented on your launch and you've shipped the fixes, say so in the thread. The re-scan is free, and if the before/after is this clean, I'll write about yours next.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>launch</category>
      <category>startup</category>
    </item>
    <item>
      <title>5 tools launched this week promising "your data never leaves your browser" — none shipped the header that enforces it</title>
      <dc:creator>Amit Feldman</dc:creator>
      <pubDate>Sun, 16 Aug 2026 13:12:38 +0000</pubDate>
      <link>https://dev.to/amitfeldman/5-tools-launched-this-week-promising-your-data-never-leaves-your-browser-none-shipped-the-c2b</link>
      <guid>https://dev.to/amitfeldman/5-tools-launched-this-week-promising-your-data-never-leaves-your-browser-none-shipped-the-c2b</guid>
      <description>&lt;p&gt;A week ago I ran a passive launch-readiness check on 10 freshly launched products and published the pattern: 7 out of 10 shipped with no &lt;code&gt;Content-Security-Policy&lt;/code&gt; at all.&lt;/p&gt;

&lt;p&gt;This week I did it again — 8 products that launched in the last ~24 hours, all "I built this" posts by solo makers. Same method: public HTTP response headers and homepage HTML only. No probing, no auth, nothing intrusive. Exactly what any scanner, prospect, or security-conscious customer sees on a single page load.&lt;/p&gt;

&lt;p&gt;I'm not naming anyone again. The pattern is the point — and this week the pattern got sharper.&lt;/p&gt;

&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;8 out of 8&lt;/strong&gt; shipped with no &lt;code&gt;Content-Security-Policy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Not 7 out of 10 this time. All of them.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Missing&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Content-Security-Policy&lt;/td&gt;
&lt;td&gt;8/8&lt;/td&gt;
&lt;td&gt;Nothing mitigating XSS / injected scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Frame-Options&lt;/td&gt;
&lt;td&gt;7/8&lt;/td&gt;
&lt;td&gt;Site can be framed anywhere → clickjacking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permissions-Policy&lt;/td&gt;
&lt;td&gt;7/8&lt;/td&gt;
&lt;td&gt;Camera/geo/mic unrestricted by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HSTS&lt;/td&gt;
&lt;td&gt;6/8&lt;/td&gt;
&lt;td&gt;First-visit downgrade possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Referrer-Policy&lt;/td&gt;
&lt;td&gt;6/8&lt;/td&gt;
&lt;td&gt;Full URLs leak to every third-party request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Content-Type-Options&lt;/td&gt;
&lt;td&gt;6/8&lt;/td&gt;
&lt;td&gt;MIME-sniffing exposure on user content&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One product came genuinely close — 5 of 6 headers present, HSTS set for two years, missing only the CSP. That's the closest anyone got.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that made me write this
&lt;/h2&gt;

&lt;p&gt;Here's the sharper pattern: &lt;strong&gt;5 of the 8 tools pitch privacy as the product.&lt;/strong&gt; "Runs in your browser." "Nothing uploaded." "Private by design." Client-side processing is the headline feature — it's in their titles and their hero copy.&lt;/p&gt;

&lt;p&gt;And every one of them shipped without the one header that actually enforces that promise.&lt;/p&gt;

&lt;p&gt;A CSP is what stops an injected script — a compromised dependency, a malicious ad tag, a poisoned CDN asset — from reading the data your users just trusted never leaves their browser. Without it, "nothing leaves your browser" is a marketing sentence, not an enforced property. One bad script tag away from being false.&lt;/p&gt;

&lt;p&gt;None of these makers are careless. Client-side processing is real engineering, and they did it. The gap is that the last mile — telling the browser "only run scripts I explicitly allow" — is a config line nobody wrote, because no test fails and no deploy breaks when it's missing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The good news: same-day fixes are real
&lt;/h2&gt;

&lt;p&gt;Yesterday I flagged a missing CSP and HSTS in the comments of one maker's launch post. By the evening he'd deployed all six security headers — CSP locked down to &lt;code&gt;script-src 'none'&lt;/code&gt;, HSTS for 180 days, the full set. His re-scan came back completely green: 16 checks passed, 0 warnings, 0 failures.&lt;/p&gt;

&lt;p&gt;Total elapsed time from "never thought about it" to "fully locked down": a few hours, in the middle of launch day.&lt;/p&gt;

&lt;p&gt;That's the actual story of these failures. Not skill, not budget — just that launch week has a hundred things in it and headers are item #101. Every fix above is a one-line config at the host or CDN layer: Vercel, Netlify, Cloudflare, nginx, all have a documented snippet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SEO side, quickly
&lt;/h2&gt;

&lt;p&gt;Better than last week — 7 of 8 had exactly one &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; and a real canonical. Remaining nits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One homepage had &lt;strong&gt;two &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tags&lt;/strong&gt; — splitting your best keyword slot against itself&lt;/li&gt;
&lt;li&gt;One meta description ran &lt;strong&gt;178 characters&lt;/strong&gt; — truncates mid-sentence in search results (~160 limit)&lt;/li&gt;
&lt;li&gt;One page took &lt;strong&gt;2.9 seconds&lt;/strong&gt; to respond, with 836ms of server think time — first impression spent staring at a blank tab&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I'd do (and did)
&lt;/h2&gt;

&lt;p&gt;Same rule as last week: a launch isn't done when the deploy succeeds — it's done when the thing a stranger's browser receives passes a baseline. Run the check before the traffic, not after.&lt;/p&gt;

&lt;p&gt;If you shipped recently and want the full picture: I run a &lt;strong&gt;Launch-Ready Quick Scan&lt;/strong&gt; — passive headers/TLS/HTML checks plus a human-written readout of what to fix first, delivered within 24h. It's $29 for the launch period (normally $49), written so you can hand it straight to whoever owns your deploy config. &lt;a href="https://afeldman2.gumroad.com/l/keikf?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=launch-scan-roundup-2" rel="noopener noreferrer"&gt;Grab one here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if your product's pitch is "private, runs in your browser": the CSP is the difference between promising it and enforcing it. Twenty minutes tonight.&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>webdev</category>
      <category>startup</category>
    </item>
    <item>
      <title>I re-scanned the launches I flagged last week — here's who actually shipped the fixes</title>
      <dc:creator>Amit Feldman</dc:creator>
      <pubDate>Sun, 16 Aug 2026 09:05:27 +0000</pubDate>
      <link>https://dev.to/amitfeldman/i-re-scanned-the-launches-i-flagged-last-week-heres-who-actually-shipped-the-fixes-514k</link>
      <guid>https://dev.to/amitfeldman/i-re-scanned-the-launches-i-flagged-last-week-heres-who-actually-shipped-the-fixes-514k</guid>
      <description>&lt;p&gt;For the past two weeks I've been running passive, read-only security scans on products that launch here on dev.to, and posting the findings publicly with the concrete fix for each. No pitch in the first touch — the scan is the conversation, and I always offer a free re-scan once fixes are deployed.&lt;/p&gt;

&lt;p&gt;The part I didn't expect: how many makers actually shipped the fixes. This is the verification roundup — real before/after numbers from the re-scans.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern across ~100 launches
&lt;/h2&gt;

&lt;p&gt;The headline finding from the &lt;a href="https://dev.to/amitfeldman/i-ran-a-passive-security-check-on-100-freshly-launched-products-here-s-what-actually-breaks-1jpn"&gt;broader sweep&lt;/a&gt; hasn't changed: the most common failure is a missing &lt;strong&gt;Content-Security-Policy&lt;/strong&gt; — roughly 7 in 10 launches — followed by missing HSTS. Both are one-line fixes. Almost nobody ships them on day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maker 1: Loop — full remediation in under 24 hours
&lt;/h2&gt;

&lt;p&gt;The fastest turnaround so far. &lt;a href="https://dev.to/jammyvibez/i-built-a-social-app-where-developers-can-share-code-fork-each-others-snippets-and-co-write-4lgl"&gt;Loop&lt;/a&gt; (Next.js on Vercel) launched with &lt;strong&gt;7 passed / 5 warnings / 4 failures&lt;/strong&gt;: no CSP, no X-Frame-Options, no nosniff, and — because the app renders client-side only — no title, meta description or h1 for crawlers and link-unfurlers.&lt;/p&gt;

&lt;p&gt;Under 24 hours later the re-scan read &lt;strong&gt;15 passed / 1 warning / 0 failures&lt;/strong&gt;. Every failing header closed. I wrote up the &lt;a href="https://dev.to/amitfeldman/one-maker-fixed-every-security-header-on-his-launch-in-24-hours-heres-the-beforeafter-5f7a"&gt;full before/after as a case study&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maker 2: Macless — 5 of 6 headers live within hours
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://macless.dev" rel="noopener noreferrer"&gt;Macless&lt;/a&gt; (ship an iOS app without a Mac) launched on GitHub Pages with all six security headers missing. GitHub Pages gives you no header control — so the maker put Cloudflare in front of the domain and used a &lt;strong&gt;Transform Rule&lt;/strong&gt; to set headers at the edge.&lt;/p&gt;

&lt;p&gt;My re-scan verified, live:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;X-Frame-Options: DENY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;X-Content-Type-Options: nosniff&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Referrer-Policy: strict-origin-when-cross-origin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Permissions-Policy&lt;/code&gt; locked down&lt;/li&gt;
&lt;li&gt;HSTS on, 180-day max-age&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Five of six, in hours. The one still open is the CSP — which is also the one doing the actual XSS work. Same fix path: one more Transform Rule, start with a tight &lt;code&gt;default-src 'self'&lt;/code&gt; and loosen only what breaks. If you're on GitHub Pages, this CDN-front pattern is the way — Pages itself will never give you these headers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maker 3: PlaygroundAPI — rescan reads 15 passed / 1 warning / 0 failures
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://playground-api-xi.vercel.app" rel="noopener noreferrer"&gt;PlaygroundAPI&lt;/a&gt; — a free sandboxed mock REST &amp;amp; GraphQL service — came back essentially clean on verification: HSTS at &lt;code&gt;max-age=63072000; includeSubDomains; preload&lt;/code&gt;, CSP defined, X-Frame-Options DENY, nosniff, Referrer-Policy and Permissions-Policy all live, TLS 1.3, 267 ms total response. The interesting surface left is the API itself — auth-flow edge cases like token expiry/reuse and session isolation — which is a manual review, not a scanner finding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maker 4: the platform-constraint case
&lt;/h2&gt;

&lt;p&gt;One launch on a &lt;code&gt;.streamlit.app&lt;/code&gt; subdomain verified their fix but hit a wall: on a platform subdomain you don't control the edge, so granular CSP and HSTS enforcement isn't yours to set. Their plan — move to a custom domain with Cloudflare and use Transform Rules — is the correct one, and the same pattern Macless used above. Platform subdomains are fine for demos; if you're collecting real users, the custom domain is part of the security posture, not just branding.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I take from this
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Makers fix things fast when the fix is concrete.&lt;/strong&gt; Every deployed fix above came from a findings comment that included the exact header line or rule to add, not a generic "you should harden your headers."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The CDN-front pattern solves the two hardest hosting cases&lt;/strong&gt; (GitHub Pages, platform subdomains) with the same move: Cloudflare in front, Transform Rules at the edge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSP is still the last one standing.&lt;/strong&gt; It's the highest-value header and the one everyone defers, because a tight CSP can break inline scripts. Ship a report-only policy first (&lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt;), watch what fires, then enforce.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Findings on launch posts stay free — the re-scan verification too. If I flagged your launch and you've shipped the fixes, reply on your thread and I'll re-run the check and post the verified numbers, same as above.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I build &lt;a href="https://dev.to/amitfeldman/i-built-a-cli-to-stop-myself-from-committing-api-keys-and-broken-envs-into-ci-3o2o"&gt;envcheck&lt;/a&gt;, a .env validator and secret-leak scanner for CI — the scans above run on the same engine.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>infosec</category>
      <category>security</category>
    </item>
    <item>
      <title>I ran a passive security check on 100 freshly launched products — 1 in 5 shipped with zero security headers</title>
      <dc:creator>Amit Feldman</dc:creator>
      <pubDate>Fri, 07 Aug 2026 22:05:07 +0000</pubDate>
      <link>https://dev.to/amitfeldman/i-ran-a-passive-security-check-on-100-freshly-launched-products-1-in-5-shipped-with-zero-security-5bn8</link>
      <guid>https://dev.to/amitfeldman/i-ran-a-passive-security-check-on-100-freshly-launched-products-1-in-5-shipped-with-zero-security-5bn8</guid>
      <description>&lt;p&gt;Last week I posted the results of checking 10 products that had just launched. The pattern was so consistent that I kept going. This is the follow-up: &lt;strong&gt;100 products&lt;/strong&gt;, all launched within roughly the past week, pulled from Product Hunt, dev.to launch posts, r/SideProject, Peerlist, Microlaunch, Uneed, and a couple of launch directories.&lt;/p&gt;

&lt;p&gt;Same rules as before — passive only. Public HTTP response headers and homepage HTML, the exact thing any scanner, prospect, or security-conscious customer sees when your site loads once. No probing, no auth attempts, nothing intrusive.&lt;/p&gt;

&lt;p&gt;And same as before: I'm not naming anyone who failed. The point is the pattern, not the callout.&lt;/p&gt;

&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Missing&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Content-Security-Policy&lt;/td&gt;
&lt;td&gt;76/100&lt;/td&gt;
&lt;td&gt;Nothing mitigating XSS / injected scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permissions-Policy&lt;/td&gt;
&lt;td&gt;78/100&lt;/td&gt;
&lt;td&gt;Camera, mic, geolocation unrestricted by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Frame-Options&lt;/td&gt;
&lt;td&gt;67/100&lt;/td&gt;
&lt;td&gt;Pages can be iframed anywhere → clickjacking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Referrer-Policy&lt;/td&gt;
&lt;td&gt;63/100&lt;/td&gt;
&lt;td&gt;Full URLs leak to every third-party request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Content-Type-Options&lt;/td&gt;
&lt;td&gt;57/100&lt;/td&gt;
&lt;td&gt;MIME-sniffing exposure on user content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HSTS&lt;/td&gt;
&lt;td&gt;37/100&lt;/td&gt;
&lt;td&gt;First-visit downgrade still possible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two numbers that surprised me even after the first batch:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;20 out of 100 shipped with all six missing.&lt;/strong&gt; Not one obscure header — every single baseline protection absent. These weren't broken products; several were polished, well-designed launches with real traction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Only 13 out of 100 were fully clean.&lt;/strong&gt; And consistent with the first batch, the clean ones skewed toward small solo projects, not the bigger teams. "More people at launch" does not mean "someone checked."&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this keeps happening
&lt;/h2&gt;

&lt;p&gt;None of these are code fixes. Every one is a config line at the host or CDN layer — Vercel, Netlify, Cloudflare, nginx, all of them have a documented snippet, and most can apply it at the edge without a deploy. The failure mode isn't skill. Launch week has a hundred things in it and "headers" is item #101. There's no test that fails, no deploy that breaks, no user who complains. The site just quietly tells every visitor's browser: &lt;em&gt;no rules, do whatever.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's exactly the class of problem that only gets caught by something that checks, every time, automatically — because humans are bad at "every time."&lt;/p&gt;

&lt;h2&gt;
  
  
  It's fixable fast — I watched it happen
&lt;/h2&gt;

&lt;p&gt;The most common pushback I got last week was "sure, but who has time during launch week?" So here's the counterexample: one maker I flagged went and fixed &lt;strong&gt;every&lt;/strong&gt; missing header within 24 hours — full before/after, verified by re-scan. I wrote it up here: &lt;a href="https://dev.to/amitfeldman/one-maker-fixed-every-security-header-on-his-launch-in-24-hours-heres-the-beforeafter-5f7a"&gt;One maker fixed every security header on his launch in 24 hours — here's the before/after&lt;/a&gt;. His site went from 5 findings to zero while I slept.&lt;/p&gt;

&lt;p&gt;If you're behind Cloudflare, four of the six are a single Transform Rule (Modify Response Header) at the edge — no code change, no deploy. HSTS starts at a short &lt;code&gt;max-age&lt;/code&gt; (3600) and steps up once verified. CSP is the one that takes actual care with a SPA, but &lt;code&gt;default-src 'self'&lt;/code&gt; plus your API origins is a safe start, and &lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt; lets you measure before you enforce.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd do differently (and do)
&lt;/h2&gt;

&lt;p&gt;My rule hasn't changed: a launch isn't done when the deploy succeeds — it's done when the thing a stranger's browser receives passes a baseline. 87 out of 100 launches this week hadn't run that check.&lt;/p&gt;

&lt;p&gt;If you shipped something recently and want to know where you stand: I run a &lt;strong&gt;Launch-Ready Quick Scan&lt;/strong&gt; — passive headers/TLS/HTML checks plus a human-written readout of what to fix first, delivered within 24h. It's $29 for the launch period (normally $49), written so you can hand it straight to whoever owns your deploy config. &lt;a href="https://afeldman2.gumroad.com/l/keikf?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=launch-scan-100" rel="noopener noreferrer"&gt;Grab one here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you're pre-launch: the six headers above are a 20-minute fix tonight. Do it before the traffic, not after.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>saas</category>
      <category>startup</category>
    </item>
    <item>
      <title>One maker fixed every security header on his launch in 24 hours — here's the before/after</title>
      <dc:creator>Amit Feldman</dc:creator>
      <pubDate>Fri, 07 Aug 2026 09:50:55 +0000</pubDate>
      <link>https://dev.to/amitfeldman/one-maker-fixed-every-security-header-on-his-launch-in-24-hours-heres-the-beforeafter-5f7a</link>
      <guid>https://dev.to/amitfeldman/one-maker-fixed-every-security-header-on-his-launch-in-24-hours-heres-the-beforeafter-5f7a</guid>
      <description>&lt;p&gt;A week ago I started leaving findings-first comments on launch posts here: I run a passive scan of the product's site, post the top findings with the concrete fix, and offer a free re-scan once it's deployed. No pitch in the first touch — the scan is the conversation.&lt;/p&gt;

&lt;p&gt;This week one maker did the thing every security person wishes more teams would do: he read the findings, deployed the fixes the same day, and asked for the re-scan. This is the before/after, with his permission-worthy win on full display.&lt;/p&gt;

&lt;h2&gt;
  
  
  The launch
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/jammyvibez/i-built-a-social-app-where-developers-can-share-code-fork-each-others-snippets-and-co-write-4lgl"&gt;Loop&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/jammyvibez"&gt;@jammyvibez&lt;/a&gt; — a collaborative social app where developers share code, fork snippets, and co-write posts live. A Next.js app on Vercel, launched here on August 5th.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before (scan, Aug 5): 7 passed / 5 warnings / 4 failures
&lt;/h2&gt;

&lt;p&gt;The good news first: HSTS was already strong (&lt;code&gt;max-age=63072000; includeSubDomains; preload&lt;/code&gt;), TLS was clean, robots.txt and sitemap.xml were live.&lt;/p&gt;

&lt;p&gt;The gaps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Content-Security-Policy&lt;/strong&gt; — the single highest-value header for an app that renders user-generated content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No X-Frame-Options&lt;/strong&gt; — clickjacking exposure on every page&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No X-Content-Type-Options, Referrer-Policy, Permissions-Policy&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;, no meta description, no &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;&lt;/strong&gt; — the app renders client-side only, so crawlers and link-unfurlers saw an empty shell&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last cluster matters more than people think: every link preview of his launch — in Discord, Slack, X, iMessage — was generating from nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  After (re-scan, Aug 6): 15 passed / 1 warning / 0 failures
&lt;/h2&gt;

&lt;p&gt;Under 24 hours later:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CSP live&lt;/strong&gt;: &lt;code&gt;default-src 'self'&lt;/code&gt; with an explicit allowlist for the two third-party origins the app actually loads (Stripe.js and Vercel Analytics)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;X-Frame-Options: DENY&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;X-Content-Type-Options: nosniff&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Referrer-Policy: strict-origin-when-cross-origin&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permissions-Policy&lt;/strong&gt;: camera/microphone scoped to self, geolocation/payment/usb locked down&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Title&lt;/strong&gt; (39 chars), &lt;strong&gt;meta description&lt;/strong&gt; (145 chars), exactly &lt;strong&gt;one H1&lt;/strong&gt; — the page now renders its metadata server-side&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The remaining backlog, which he has in writing: &lt;code&gt;script-src&lt;/code&gt; still carries &lt;code&gt;'unsafe-inline' 'unsafe-eval'&lt;/code&gt; (a Next.js hydration constraint you close with nonces when it matters), and TTFB is ~2.1s cold. Neither is a launch blocker. Both are honest items on a real list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three takeaways for anyone launching this week
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Headers are a config file, not a sprint.&lt;/strong&gt; On Vercel it's a &lt;code&gt;headers()&lt;/code&gt; block in &lt;code&gt;next.config.js&lt;/code&gt; or entries in &lt;code&gt;vercel.json&lt;/code&gt;. On Netlify it's a &lt;code&gt;_headers&lt;/code&gt; file. Behind Cloudflare it's one Transform Rule at the edge — no deploy at all. The entire "after" column above was one commit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. If your app is client-rendered, your metadata doesn't exist.&lt;/strong&gt; Crawlers, link unfurlers, and most social scrapers don't execute JavaScript. SSR/SSG your &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;, meta description, and at least one &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; — or accept that every share of your launch looks blank.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Ship CSP in report-only mode first.&lt;/strong&gt; &lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt; tells you what would break without breaking it. Let violation reports collect for a few days, allowlist what you actually load, then enforce. Loop's CSP is a good enforced end-state: &lt;code&gt;default-src 'self'&lt;/code&gt; plus exactly the origins you use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm telling this story
&lt;/h2&gt;

&lt;p&gt;Because this is the loop that works: findings → fix → verified re-scan. &lt;a class="mentioned-user" href="https://dev.to/jammyvibez"&gt;@jammyvibez&lt;/a&gt; didn't pay anyone for this — the first scan and the re-scan were free, and now his launch passes checks that show up verbatim in enterprise security questionnaires.&lt;/p&gt;

&lt;p&gt;I run these scans as &lt;a href="https://afeldman2.gumroad.com/l/keikf?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=casestudy-loopapp" rel="noopener noreferrer"&gt;Launch-Ready Quick Scans&lt;/a&gt; — $29 during launch period, top findings plus the full report — and I keep commenting findings-first on launch posts here regardless. If I commented on yours and you've shipped the fixes, say so in the thread. The re-scan is free, and if the before/after is this clean, I'll write about yours next.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>saas</category>
      <category>startup</category>
    </item>
    <item>
      <title>I ran a passive security check on 10 products that launched this week — 7 failed the same one-line fix</title>
      <dc:creator>Amit Feldman</dc:creator>
      <pubDate>Wed, 05 Aug 2026 00:05:18 +0000</pubDate>
      <link>https://dev.to/amitfeldman/i-ran-a-passive-security-check-on-10-products-that-launched-this-week-7-failed-the-same-one-line-1ie1</link>
      <guid>https://dev.to/amitfeldman/i-ran-a-passive-security-check-on-10-products-that-launched-this-week-7-failed-the-same-one-line-1ie1</guid>
      <description>&lt;p&gt;This week I did something I've been meaning to do for a while: I took 10 products that launched in the last 48 hours — a mix of Product Hunt launches and "I built this" posts on Reddit — and ran a passive launch-readiness check on each one.&lt;/p&gt;

&lt;p&gt;Passive means exactly that: public HTTP response headers and homepage HTML only. No probing, no auth attempts, nothing intrusive — the same thing any scanner, prospect, or security-conscious customer sees when they load your site once.&lt;/p&gt;

&lt;p&gt;I'm not naming anyone. The point isn't to call out individual makers — it's that the failures were so consistent they form a pattern worth publishing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;7 out of 10&lt;/strong&gt; shipped with no &lt;code&gt;Content-Security-Policy&lt;/code&gt; header at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3 out of 10&lt;/strong&gt; were missing &lt;code&gt;Strict-Transport-Security&lt;/code&gt; — including one product ranked #1 on Product Hunt the day it launched.&lt;/p&gt;

&lt;p&gt;Across the 10 sites, the most common gaps, in order:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Failed&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Content-Security-Policy&lt;/td&gt;
&lt;td&gt;7/10&lt;/td&gt;
&lt;td&gt;Nothing mitigating XSS / injected scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Referrer-Policy&lt;/td&gt;
&lt;td&gt;6/10&lt;/td&gt;
&lt;td&gt;Full URLs leak to every third-party request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permissions-Policy&lt;/td&gt;
&lt;td&gt;6/10&lt;/td&gt;
&lt;td&gt;Camera/geo/mic features unrestricted by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Frame-Options&lt;/td&gt;
&lt;td&gt;6/10&lt;/td&gt;
&lt;td&gt;Site can be framed anywhere → clickjacking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Content-Type-Options&lt;/td&gt;
&lt;td&gt;6/10&lt;/td&gt;
&lt;td&gt;MIME-sniffing exposure on user content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HSTS&lt;/td&gt;
&lt;td&gt;3/10&lt;/td&gt;
&lt;td&gt;First-visit downgrade possible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two products were genuinely clean — all six headers present, HSTS with preload. Both were small solo projects, which killed my assumption that "bigger launch = better hygiene."&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this keeps happening
&lt;/h2&gt;

&lt;p&gt;None of these are code fixes. Every one is a one-line config change at the host or CDN layer — Vercel, Netlify, Cloudflare, nginx, all of them have a documented snippet for it. The failure mode isn't skill, it's that launch week has a hundred things in it and "headers" is item #101. There's no test that fails, no deploy that breaks, no user who complains. The site just quietly tells every visitor's browser "no rules, do whatever."&lt;/p&gt;

&lt;p&gt;That's exactly the class of problem that only gets caught by something that checks, every time, automatically — because humans are bad at "every time."&lt;/p&gt;

&lt;h2&gt;
  
  
  The SEO side wasn't much better
&lt;/h2&gt;

&lt;p&gt;While I was in the HTML I checked the basics too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2/10 homepages had &lt;strong&gt;no &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;&lt;/strong&gt; — your single best keyword slot, empty&lt;/li&gt;
&lt;li&gt;Meta descriptions over 200 chars (truncates at ~160 in search results) on half of them&lt;/li&gt;
&lt;li&gt;One product had a meta description of &lt;strong&gt;2,701 characters&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Missing &lt;code&gt;alt&lt;/code&gt; text on the majority of images on 8/10 sites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Again: not skill. Just nobody checked.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd do differently (and did)
&lt;/h2&gt;

&lt;p&gt;I run these checks on every launch now, including my own. My rule is simple: a launch isn't done when the deploy succeeds — it's done when the thing a stranger's browser receives passes a baseline.&lt;/p&gt;

&lt;p&gt;If you shipped something recently and want to know where you stand: I run a &lt;strong&gt;Launch-Ready Quick Scan&lt;/strong&gt; — passive headers/TLS/HTML checks plus a human-written readout of what to fix first, delivered within 24h. It's $29 for the launch period (normally $49), and the report is written so you can hand it straight to whoever owns your deploy config. &lt;a href="https://afeldman2.gumroad.com/l/keikf?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=launch-scan-roundup" rel="noopener noreferrer"&gt;Grab one here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you're pre-launch: the six headers above are a 20-minute fix tonight. Do it before the traffic, not after.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I run a one-person company — here are the 54 prompts I actually reuse</title>
      <dc:creator>Amit Feldman</dc:creator>
      <pubDate>Thu, 30 Jul 2026 07:43:36 +0000</pubDate>
      <link>https://dev.to/amitfeldman/i-run-a-one-person-company-here-are-the-54-prompts-i-actually-reuse-4h0h</link>
      <guid>https://dev.to/amitfeldman/i-run-a-one-person-company-here-are-the-54-prompts-i-actually-reuse-4h0h</guid>
      <description>&lt;h2&gt;
  
  
  Four jobs before lunch
&lt;/h2&gt;

&lt;p&gt;A normal Tuesday for me: 9am I'm a developer, 11am I'm writing landing page copy, 1pm I'm on a discovery call pretending I have a sales process, 3pm an angry email lands and I'm support, 5pm I'm doing the invoicing I've been avoiding since Friday.&lt;/p&gt;

&lt;p&gt;The work isn't the expensive part. The &lt;em&gt;switching&lt;/em&gt; is. Every hop lands me in front of a blank page in a role I'm mediocre at, and I lose fifteen minutes just working out what good even looks like here. Four hops a day, five days a week. That's most of a working day a week spent staring.&lt;/p&gt;

&lt;p&gt;So I did what everyone does now: I asked an AI assistant. "Help me write a cold email." "How should I price this?" And I got exactly what you'd expect — competent, structureless mush. Advice that sounds like a LinkedIn post. The problem wasn't the model. It was that I was asking like someone who didn't know the domain, because in that particular hour, I didn't.&lt;/p&gt;

&lt;p&gt;The fix turned out to be boring: stop asking questions, start pasting &lt;em&gt;briefs&lt;/em&gt;. A prompt that names a framework, hands over real numbers, sets constraints, and demands a decision rule at the end gets back something I can act on. One that doesn't gets a fortune cookie.&lt;/p&gt;

&lt;p&gt;I kept the ones that worked in a file. That file is now 54 prompts across the six jobs I actually do — validation, marketing, sales, ops, finance, support — and I've packaged it up. Here are three of them in full, so you can judge the pattern yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The prompt I run before I build anything
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When to use this:&lt;/strong&gt; when you're in love with an idea and need a hostile reviewer to try to kill it before the market does.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Act as a skeptical seed-stage investor who has seen 1,000 pitches and passed on
most of them. Here is my idea:

[DESCRIBE THE IDEA IN 3–5 SENTENCES: who it's for, the problem, the solution,
and how it makes money]

Tear it apart. Specifically:
1. Name the 3 assumptions most likely to be fatally wrong, ranked by
   (likelihood of being wrong) × (damage if wrong).
2. For each, describe the cheapest test (under $100 and under one week) that
   would produce real evidence either way.
3. List who already solves this and why customers might prefer the status quo,
   spreadsheets, or doing nothing.
4. Tell me what evidence would change your mind from "pass" to "curious."

Be direct. Do not soften the critique and do not end with encouragement.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why it works: the ranking formula stops the model listing ten generic risks and forces a prioritisation. "Under $100 and under one week" converts criticism into this week's to-do list. And the last line matters more than it looks — without it you get a paragraph of encouragement at the end that quietly undoes the whole exercise.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The prompt that gets my week back
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When to use this:&lt;/strong&gt; when your week disappears into repetitive admin and you need to know what to automate first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an automation consultant. I'm a solo founder. Here is how I
actually spent my time last week, with hours per task:

[PASTE YOUR TASK LIST, e.g. "answering support emails 4h, invoicing 1h,
scheduling social posts 2h, sales calls 5h, writing content 4h…"]

1. Score every task on two axes: repetitiveness (how rule-based is it)
   and founder-necessity (does it need MY judgment/relationship).
2. Sort all tasks into four quadrants: automate now, delegate, keep
   but time-box, and eliminate.
3. For the top 3 "automate now" candidates, rank by ROI =
   (hours saved per month) ÷ (setup effort), and describe the
   automation for each: trigger, steps, tools ([MY STACK, e.g. "Gmail,
   Stripe, Notion, Zapier/Make"]), and failure mode to watch.
4. Estimate total hours recovered per month and tell me the ONE
   automation to build this week.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why it works: it runs on &lt;em&gt;your&lt;/em&gt; logged hours, not a hypothetical founder's, so the output can't be generic. And step 4 is the whole point — a list of twelve automation ideas is another form of paralysis. I want one.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The prompt for the email I shouldn't send at 11pm
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When to use this:&lt;/strong&gt; when a furious email lands and your first-draft reply would make things worse.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a customer-success lead who specializes in saving angry
customers. My product: [PRODUCT DESCRIPTION]. Here is the customer's
message:

[PASTE THE ANGRY MESSAGE]

And here is what actually happened / what I can offer: [FACTS + WHAT
YOU CAN DO: refund, fix timeline, workaround, nothing].

Write my reply:
1. First, tell me privately (not for the customer): is this customer
   right? What did we likely get wrong?
2. The reply itself, under 150 words: acknowledge the specific
   failure without legal-speak or "we're sorry you feel that way",
   take ownership of what's genuinely ours, state what I'm doing
   about it with a concrete action and date, and make the remedy
   (if any) without them having to ask again.
3. One sentence I must NOT send (the defensive thing I'm tempted to
   say) and why.
4. A follow-up note to send [N] days later checking the fix landed —
   this is where angry customers become loyal ones.
5. The product/process fix I should make so this exact ticket never
   happens again.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 1 and step 3 are why I still use this one. The private read on whether the customer is &lt;em&gt;right&lt;/em&gt; usually deflates my defensiveness before I've written a word, and naming the sentence I'm tempted to send is unnervingly accurate about every time.&lt;/p&gt;

&lt;p&gt;They're also built to chain: interview notes from the Mom Test script feed the testimonial-to-copy miner, whose output feeds the landing-page hero prompt. Outputs become inputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this is not for
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If you already have a playbook, skip it.&lt;/strong&gt; Someone who's run sales or done pricing work professionally will find their own frameworks in here with the serial numbers filed off. The pack is for people covering six roles badly, not one role well.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's prompts, not software.&lt;/strong&gt; Markdown files plus one print-ready HTML page. Nothing runs, nothing integrates, no accounts. If you want a tool, this isn't one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The placeholders are work.&lt;/strong&gt; Every prompt wants real numbers, real quotes, real transcripts. Fill them with vagueness and you get vagueness back — the specificity is doing the heavy lifting, not the wording.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It won't make the decision for you.&lt;/strong&gt; Several prompts deliberately end in a scorecard or a pass/fail rule. That's a structured argument to react to, not an answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting it
&lt;/h2&gt;

&lt;p&gt;The Solo Founder's AI Prompt Pack is $19 on Gumroad: &lt;strong&gt;&lt;a href="https://afeldman2.gumroad.com/l/zdyxz?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=promptpack-launch" rel="noopener noreferrer"&gt;https://afeldman2.gumroad.com/l/zdyxz?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=promptpack-launch&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;54 prompts across six categories, organised Markdown for daily copy-paste plus a single styled HTML file you can print to PDF. Works with any assistant that takes a long prompt — ChatGPT, Claude, Gemini, whatever you already pay for.&lt;/p&gt;

&lt;p&gt;And if you just take the three above and never buy anything: genuinely fine. The pattern — name a framework, hand over real data, constrain the output, demand a decision rule — is the part worth stealing.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I built a one-command website auditor because discovery calls were eating my afternoons</title>
      <dc:creator>Amit Feldman</dc:creator>
      <pubDate>Thu, 30 Jul 2026 06:08:23 +0000</pubDate>
      <link>https://dev.to/amitfeldman/i-built-a-one-command-website-auditor-because-discovery-calls-were-eating-my-afternoons-45p3</link>
      <guid>https://dev.to/amitfeldman/i-built-a-one-command-website-auditor-because-discovery-calls-were-eating-my-afternoons-45p3</guid>
      <description>&lt;h2&gt;
  
  
  The discovery-call scramble
&lt;/h2&gt;

&lt;p&gt;If you freelance or run a small agency, you know this moment: a prospect gets on a call and asks, "So what's wrong with our current site?" And you need a credible, concrete answer — not "well, I'd have to dig into it," and not forty minutes of manually opening dev tools, checking headers with curl, running PageSpeed, and eyeballing the source for a meta description.&lt;/p&gt;

&lt;p&gt;I got tired of the scramble, so I wrote it down as a checklist, then turned the checklist into a script. It's called &lt;strong&gt;siteprobe&lt;/strong&gt;: one Python file, zero dependencies, standard library only. Point it at a URL and it audits the things clients actually care about — speed, security headers, TLS certificate, and on-page SEO — in about five seconds. Add one flag and it emits a polished HTML report you can attach to a proposal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 siteprobe.py https://example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No install, no API keys, no accounts. Python 3.9+ is the only requirement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What one run actually tells you
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Speed, broken down usefully.&lt;/strong&gt; "Your site is slow" is useless; "your TLS handshake is 800ms because the cert chain is misconfigured" is a fix. siteprobe measures with raw sockets and reports each phase separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⏱ Timing
  DNS resolution     12 ms
  TCP connect        34 ms
  TLS handshake      87 ms
  Time to first byte 412 ms
  Total              545 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Security headers, with fixes.&lt;/strong&gt; It checks the six headers on every audit checklist — HSTS, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy — and every missing one comes back as a PASS/WARN/FAIL finding with copy-paste fix advice, not just "missing."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLS certificate expiry.&lt;/strong&gt; Issuer, expiry date, days remaining, negotiated protocol and cipher. It warns under 30 days and fails on expired. If you've ever had a client's site go down because nobody tracked a cert renewal, you know why this is its own line item.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On-page SEO signals.&lt;/strong&gt; Title tag (with length check), meta description, H1 count, images missing &lt;code&gt;alt&lt;/code&gt; attributes, canonical link, viewport meta — plus live checks that &lt;code&gt;/robots.txt&lt;/code&gt; and &lt;code&gt;/sitemap.xml&lt;/code&gt; actually exist and respond.&lt;/p&gt;

&lt;p&gt;The terminal output ends with a summary count, so a run looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ 9 passed   ⚠ 3 warnings   ✗ 2 failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follows redirects automatically too (up to 10 hops, with the per-hop status codes shown), so &lt;code&gt;python3 siteprobe.py http://github.com&lt;/code&gt; tells you the whole story of the redirect chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that's actually worth paying for
&lt;/h2&gt;

&lt;p&gt;The terminal audit is nice. The deliverable is the point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 siteprobe.py https://client-site.com &lt;span class="nt"&gt;--html&lt;/span&gt; report.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--html&lt;/code&gt; writes a self-contained HTML report — inline CSS, no external assets, no branding to strip out — with styled tables and an overall verdict banner at the top. It's designed to be forwarded to a client or attached to an invoice exactly as it lands on disk. The discovery-call scramble becomes: run one command before the call, attach the report to the proposal after it.&lt;/p&gt;

&lt;p&gt;It's also cron/CI-friendly. Exit codes are 0 (all passed), 1 (warnings only), 2 (at least one failure), so a weekly cron job that re-audits your client sites and alerts on exit code 2 is about four lines of crontab. That turns a one-off audit into ongoing monitoring — cert expiry warnings especially.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It's not a crawler.&lt;/strong&gt; siteprobe audits the URL you give it (plus robots.txt and sitemap.xml). It doesn't spider the whole site, so per-page SEO issues on page 47 won't show up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TTFB, not full rendering.&lt;/strong&gt; The timing is server response, measured with raw sockets. It doesn't run a headless browser, so Core Web Vitals, layout shift, and JS-bundle bloat are out of scope — that's Lighthouse/PageSpeed territory, and the two tools complement each other fine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Header checks are presence-and-sanity, not policy review.&lt;/strong&gt; It will tell you CSP is missing; it won't audit whether your existing CSP is well-designed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single URL per run.&lt;/strong&gt; Script it in a loop if you want a batch; there's no built-in site list mode.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting it
&lt;/h2&gt;

&lt;p&gt;siteprobe is $12 (pay-what-you-want, $12 minimum) on Gumroad: &lt;strong&gt;&lt;a href="https://afeldman2.gumroad.com/l/chwsxj?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=siteprobe-launch" rel="noopener noreferrer"&gt;https://afeldman2.gumroad.com/l/chwsxj?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=siteprobe-launch&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You get the single MIT-licensed Python file plus a test suite that spins up a local HTTP server and covers fetching, timing, redirects, header detection, SEO parsing, and HTML report rendering — no network needed to verify it works. If one audit report helps you close one proposal, it's paid for itself several times over.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>freelance</category>
      <category>productivity</category>
      <category>python</category>
    </item>
    <item>
      <title>I stopped doing free work — the scope language and change-order email that saved me unpaid weeks</title>
      <dc:creator>Amit Feldman</dc:creator>
      <pubDate>Wed, 29 Jul 2026 09:19:07 +0000</pubDate>
      <link>https://dev.to/amitfeldman/i-stopped-doing-free-work-the-scope-language-and-change-order-email-that-saved-me-unpaid-weeks-kj4</link>
      <guid>https://dev.to/amitfeldman/i-stopped-doing-free-work-the-scope-language-and-change-order-email-that-saved-me-unpaid-weeks-kj4</guid>
      <description>&lt;h2&gt;
  
  
  The drip that ate the project
&lt;/h2&gt;

&lt;p&gt;The project was fixed-price. We had a kickoff call, a rough list of pages, a number both of us liked. Then the drip started.&lt;/p&gt;

&lt;p&gt;"One quick tweak on the hero." "While you're in there, can you wire up the contact form to our CRM?" "My partner saw the design and wants a different direction — nothing major." Each ask was small. None of them were in the quote. Three weeks later I'd done maybe 40% more work than I'd priced, the revisions had no end in sight, and the final invoice sat unread in their inbox.&lt;/p&gt;

&lt;p&gt;This isn't a story about villains. The client wasn't trying to steal hours. Nothing in writing ever told either of us where the line was. "Two rounds of revisions" sounds clear until you need a test for &lt;em&gt;what counts as a revision&lt;/em&gt; — and by then you're already doing the work free, because saying no mid-project feels worse than saying nothing.&lt;/p&gt;

&lt;p&gt;I'd had that project more than once. Free templates were one vague page. Contract SaaS wanted a subscription forever for forms I'd fill out once. So I stopped hoping the next client would be different and wrote the system I wish I'd had on day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The system, not the pile
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ScopeGuard&lt;/strong&gt; is a scope-defense pack for fixed-price freelancers: SOW template, revision policy, one-page change-order form, payment terms (deposit, milestones, late fees, work-pause, kill fee), twelve email scripts, a rate card, and a 20-question scope audit you run &lt;em&gt;before&lt;/em&gt; you quote. Markdown masters plus a print-ready PDF. $19, one-time.&lt;/p&gt;

&lt;p&gt;The order matters more than any single document:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Before quoting&lt;/strong&gt; — audit the brief for scope bombs (committee approvals, "modern like Apple," content that's "almost ready").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Before starting&lt;/strong&gt; — SOW with explicit in-scope / out-of-scope lists and measurable "done," plus a revision policy that makes revision-vs-change a fact instead of a fight.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mid-project&lt;/strong&gt; — every request sorted in seconds: in-scope, free revision (within rounds), or change (priced and signed before work starts).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If money stalls&lt;/strong&gt; — escalate on rails: nudge → direct → final notice → pause → kill fee, each email already written.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Clients usually respect the process because it's professional, not because it's rigid. The change order is one page: what changed, price, timeline impact, signature. No signed form, no work. One unbilled "quick favor" teaches them the system is decorative — so the pack only works if you use it every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two lines that do most of the work
&lt;/h2&gt;

&lt;p&gt;The revision policy's job is to kill the two most expensive sentences in freelancing: "can you just tweak this one thing?" and "that's not what I meant." The tests are short enough to paste into a reply:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revision test:&lt;/strong&gt; If the request references something already written down in the SOW (a spec, approved mockup, brand guide, test) and asks for the work to match it — it's a revision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Change test:&lt;/strong&gt; If the request introduces something not written down in the SOW, or reverses something the client already approved in writing — it's a change, priced on a Change Order before any work starts.&lt;/p&gt;

&lt;p&gt;Rule of thumb: &lt;em&gt;Revisions make the agreed work right. Changes make different work.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When included rounds run out, the client gets two options: pay for another round, or approve as-is. Silence past the review window is acceptance. That last bit alone stops the endless "almost there" loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The email I used to rewrite every time
&lt;/h2&gt;

&lt;p&gt;The scripts are meant to be sent with brackets filled — warm but immovable. Here's the gentle first pushback when something small sits outside the SOW:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Happy to help with this. Before I dive in — this one sits outside what we scoped in the SOW ([Section 3, "Out of Scope"]). It's a small thing, so here's what I'd suggest: I can fold it in as a mini change order for $[amount], which keeps us both honest on scope, or we can park it on a list for a post-launch phase if you'd rather keep this phase lean.&lt;/p&gt;

&lt;p&gt;Either way, the current timeline isn't affected. Which would you prefer?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When the quick tweaks become a pattern, the firm version lists the recent out-of-scope asks, says you've absorbed them so far, and attaches a drafted change order — in-scope work continues either way. You're not arguing about fairness; you're pointing at the document they already signed.&lt;/p&gt;

&lt;p&gt;There's also a kickoff email that sets the rule before the first "while you're at it": ideas are welcome; each one is sorted into "in scope — done" or "priced option — your call." That turns the change order into a decision tool, not a penalty.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It's documents, not magic.&lt;/strong&gt; Templates don't enforce themselves. If you skip the change order once, you've trained the client that the boundary is optional.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not legal advice.&lt;/strong&gt; Practical business language only. Contract and payment rules vary by place — have a lawyer review the terms for your jurisdiction before you lean on them in a dispute.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You still adapt the brackets.&lt;/strong&gt; Deposit %, revision rounds, rates, late fees — set them once and keep them consistent. Inconsistent terms are how scope arguments start.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It won't fix a project you should have declined.&lt;/strong&gt; The audit checklist is there so bad deals die before the deposit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting it
&lt;/h2&gt;

&lt;p&gt;ScopeGuard is $19 on Gumroad: &lt;strong&gt;&lt;a href="https://afeldman2.gumroad.com/l/chliwp?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=scopeguard-launch" rel="noopener noreferrer"&gt;https://afeldman2.gumroad.com/l/chliwp?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=scopeguard-launch&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instant download — SOW, revision policy, change-order form, payment terms, 12 scripts, rate card, scope audit, and a print-ready PDF. One caught scope bomb or one on-time invoice covers it many times over.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I built a CLI to stop myself from committing API keys (and broken .env files)</title>
      <dc:creator>Amit Feldman</dc:creator>
      <pubDate>Tue, 28 Jul 2026 20:32:15 +0000</pubDate>
      <link>https://dev.to/amitfeldman/i-built-a-cli-to-stop-myself-from-committing-api-keys-and-broken-env-filesi-built-a-cli-to-stop-5eg8</link>
      <guid>https://dev.to/amitfeldman/i-built-a-cli-to-stop-myself-from-committing-api-keys-and-broken-env-filesi-built-a-cli-to-stop-5eg8</guid>
      <description>&lt;h2&gt;
  
  
  The 11pm key rotation
&lt;/h2&gt;

&lt;p&gt;Two things have burned me more than once, and I suspect they've burned you too.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Want this run on YOUR app before launch?&lt;/strong&gt; I run envcheck plus a site-side pass on your repo + production URL and hand back a severity-ranked findings report in 48h — &lt;strong&gt;$29 launch price&lt;/strong&gt; → &lt;a href="https://afeldman2.gumroad.com/l/keikf?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=envcheck-cta" rel="noopener noreferrer"&gt;https://afeldman2.gumroad.com/l/keikf?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=envcheck-cta&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Incident one:&lt;/strong&gt; a deploy that went green in CI and then crashed on boot in production because &lt;code&gt;.env.production&lt;/code&gt; was missing &lt;code&gt;REDIS_URL&lt;/code&gt;. Nobody caught it, because nothing in the pipeline actually compared the production env file against the keys the app expects. The error message was something unhelpful like &lt;code&gt;undefined is not a function&lt;/code&gt; three stack frames away from the real problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incident two:&lt;/strong&gt; a Stripe test key committed to a repo that was later flipped from private to public. It was a &lt;em&gt;test&lt;/em&gt; key, thankfully, but I still spent an evening rotating it, scrubbing history, and writing the postmortem nobody reads.&lt;/p&gt;

&lt;p&gt;Both of these are embarrassingly common, and both are cheap to catch — you just have to actually check, every build, forever. Humans are bad at "every build, forever." Scripts are good at it. So I wrote one: &lt;strong&gt;envcheck&lt;/strong&gt;, a zero-dependency Node CLI that does two jobs — validating &lt;code&gt;.env&lt;/code&gt; files, and scanning repos for leaked secrets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Job 1: Is my env config sane?
&lt;/h2&gt;

&lt;p&gt;The simplest mode compares an env file against your committed &lt;code&gt;.env.example&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;envcheck check .env &lt;span class="nt"&gt;--example&lt;/span&gt; .env.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a deliberately broken file, that prints something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.env
  ✗ missing-key      DATABASE_URL is required by .env.example but absent
  ✗ duplicate-key    PORT defined on line 3 and line 9
  ⚠ empty-value      SENTRY_DSN has no value
  ⚠ placeholder-default  API_KEY still equals the example default

1 errors, 2 warnings — 4 keys checked
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;placeholder-default&lt;/code&gt; warning is my favorite. It catches the case where someone copied &lt;code&gt;.env.example&lt;/code&gt; to &lt;code&gt;.env&lt;/code&gt; and forgot to fill in a real value — so the app boots with &lt;code&gt;API_KEY=your-key-here&lt;/code&gt; and fails somewhere downstream with a confusing auth error.&lt;/p&gt;

&lt;p&gt;When you want more than "same keys as the example," there's a JSON schema format with per-key types, patterns, enums, and length rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"DATABASE_URL"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"allowExtra"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"port"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"NODE_ENV"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"development"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"minLength"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;envcheck check .env.production --schema env.schema.json --strict&lt;/code&gt; fails the build on warnings too. This is the check that would have saved my crashed deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Job 2: Am I about to commit a secret?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;envcheck scan &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This recursively scans the repo for two classes of problems: known token formats (AWS access keys, GitHub and GitLab tokens, Stripe keys, Slack tokens, Google API keys, JWTs, &lt;code&gt;-----BEGIN PRIVATE KEY-----&lt;/code&gt; blocks, and a dozen more), plus generic &lt;code&gt;password = "…"&lt;/code&gt; / &lt;code&gt;api_key: …&lt;/code&gt; assignments filtered by Shannon entropy — which catches random-looking tokens nobody wrote a regex for.&lt;/p&gt;

&lt;p&gt;Output looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/config.js:12:15  ✗ github-token   possible GitHub token   ghp_…89 (40 chars)
deploy/notes.txt:4   ✗ high-entropy   high-entropy string     7Kd2…Qz (36 chars)
.env                 ✗ env-file       .env file present in scanned tree

2 errors — 42 files scanned, 3 skipped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few design decisions that matter in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Matches are redacted.&lt;/strong&gt; Reports are safe to archive as CI artifacts; envcheck never prints your full secret.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Noise control is built in.&lt;/strong&gt; &lt;code&gt;node_modules&lt;/code&gt;, lockfiles, minified files, source maps, and binaries are skipped automatically, and placeholder values like &lt;code&gt;your-key-here&lt;/code&gt; don't cry wolf. A scanner that floods you with false positives gets disabled within a week.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit codes are boring on purpose.&lt;/strong&gt; 0 = clean, 1 = findings, 2 = usage error. Every CI system on earth understands that.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What CI integration looks like
&lt;/h2&gt;

&lt;p&gt;GitHub Actions, in full:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;22&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx envcheck check .env.ci --example .env.example --strict&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx envcheck scan . --json &amp;gt; envcheck-report.json&lt;/span&gt;
  &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole thing. Zero runtime dependencies, nothing to configure, works offline, Node 18+. It also exposes &lt;code&gt;--json&lt;/code&gt; on every command if you want to feed results into your own tooling, and a programmatic API (&lt;code&gt;parseEnv&lt;/code&gt;, &lt;code&gt;validateEnv&lt;/code&gt;, &lt;code&gt;scanContent&lt;/code&gt;) if you want to embed it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It's a scanner, not a vault.&lt;/strong&gt; It finds secrets in files; it doesn't manage them. If you need secret storage, that's Vault/Doppler/1Password territory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entropy detection has a floor.&lt;/strong&gt; Short random tokens (under ~20 chars) often don't have enough entropy to distinguish from normal identifiers. The known-format regexes cover the common cases; genuinely obscure short tokens can slip through.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It won't catch a secret that's already in git history&lt;/strong&gt; — it scans working-tree files, not &lt;code&gt;git log&lt;/code&gt;. If a key was committed and deleted, you still need to rotate it. (Rotate it. Scrubbing history is not enough.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node-only runtime.&lt;/strong&gt; The validation logic is plain JS with no dependencies, so porting is feasible, but today you need Node 18+.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting it
&lt;/h2&gt;

&lt;p&gt;envcheck is &lt;strong&gt;free&lt;/strong&gt; on Gumroad: &lt;strong&gt;&lt;a href="https://afeldman2.gumroad.com/l/yxtnc?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=envcheck-launch" rel="noopener noreferrer"&gt;https://afeldman2.gumroad.com/l/yxtnc?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=envcheck-launch&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That gets you the complete MIT-licensed source (audit every line — it's yours), the schema format docs, example files including a deliberately-broken env file for demos, and the full 65-test suite so you can verify it does what this post claims. Cheaper than one evening of rot### Want this run on your app instead?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Launch-Ready Quick Scan ($29, 48h):&lt;/strong&gt; I run envcheck plus a site-side scanner on your repo + live URL — leaked credentials, &lt;code&gt;.env&lt;/code&gt; drift, security headers, TLS expiry, and the config mistakes that only show up in production. You get a severity-ranked report with a prioritized fix list. → &lt;a href="https://afeldman2.gumroad.com/l/keikf?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=envcheck-quickscan" rel="noopener noreferrer"&gt;https://afeldman2.gumroad.com/l/keikf?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=envcheck-quickscan&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Launch-Ready Audit ($99):&lt;/strong&gt; everything in the Quick Scan plus a manual review of your auth flow, CI secrets, and exposed routes, and a fix plan ordered by what actually matters for your app rather than by scanner severity. → &lt;a href="https://afeldman2.gumroad.com/l/zxpluh?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=envcheck-audit" rel="noopener noreferrer"&gt;https://afeldman2.gumroad.com/l/zxpluh?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=envcheck-audit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not a pentest, and I say so in the report — it's the boring-misconfiguration layer that takes down launches. What the pass catches, with real before/afters: &lt;a href="https://dev.to/amitfeldman/all-six-security-headers-fixed-in-a-day-the-macless-beforeafter-5343"&gt;all six security headers fixed in a day (Macless)&lt;/a&gt; and &lt;a href="https://dev.to/amitfeldman/one-maker-fixed-every-security-header-on-his-launch-in-24-hours-heres-the-beforeafter-5f7a"&gt;every security header fixed in 24 hours (LoopApp)&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
  </channel>
</rss>
