I run a Dutch health AI platform alone. No co-founder, no CTO, no security team. Last Friday I shipped a security pipeline that, on paper, sits somewhere between what a 50-person scale-up and a Series-A startup deploys.
Total cost of running it: €2.60 per year in LLM tokens. Total time to build it: one day, with Claude doing the typing.
This isn't a "vibe coding wins" piece. This is the architecture, the code, what it catches, what it misses, and why I'm telling you most of your competitors are running production with a glass door and no lock on it.
The state of solo-founder security in 2026 (it's grim)
Some numbers, because opinions are cheap:
- ~28% of the top 100K websites have Content Security Policy headers (Mozilla Observatory, 2025)
- ~60% of Stripe integrations don't validate webhook signatures (Stripe's own engineering blog)
- ~70% of public websites run dependencies with known CVEs older than six months
- A typical WordPress shop has CSP off, no rate-limiting on
/wp-login.php, plugin files indexed in Google, and an admin email that is also the recovery email
The "we're too small to be a target" defense died around 2021 when AI-driven scanners like Nuclei, Burp Suite, ZAP, and (since 2024) XBOW and ZeroPath started crawling the internet 24/7. They don't pick targets. They scan everyone, score what they find, and the high-yield findings go up the pipe for follow-up.
If you're shipping production code as a solo founder, the question is no longer "will I get attacked." It's "will the attacker bother spending more than three minutes once their scanner has scored my site."
That's the bar I wanted to clear in one day.
What I have now (the six components)
┌──────────────────────────────────────────┐
│ 1. SecurityRadar (Friday 03:30 NL) │
│ → NVD + GH Advisories + npm audit + RSS │
│ → Haiku-classify on shortlist │
│ → Critical = direct email + admin UI │
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ 2. Dependabot (weekly Saturday) │
│ → Auto-PRs to dev branch only │
│ → Major bumps ignored (no breaking) │
│ → Grouped to reduce noise │
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ 3. Auto-merge bot on dev │
│ → Squash-merge once CI is green │
│ → Major-bump PRs: skipped, await human │
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ 4. Muraqib nightly (Playwright on dev) │
│ → 90 end-to-end specs against dev URL │
│ → Result logged in GitHub Actions │
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ 5. dev → main promotion (daily 09:00) │
│ → Requires 7 consecutive green Muraqib │
│ → Risk-gate on protected files │
│ → Fast-forward merge + push │
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ 6. Auto-rollback (post-push to main) │
│ → Wait 90s, poll /api/health for 15 min │
│ → 3 consecutive 5xx = git revert + push │
│ → Email alert + [skip rollback] guard │
└──────────────────────────────────────────┘
Six moving parts. Each is the simplest possible implementation of its job. None of them are clever. The cleverness is that they're chained.
Component 1: SecurityRadar (the eyes)
The radar runs once a week, Friday 03:30 NL. It hits four sources, all free:
-
npm audit --jsonon the local lockfile - GitHub Security Advisories REST API, scoped to packages I actually use
- NIST NVD recent CVEs, last seven days, filtered to my stack keywords
- RSS feeds from Stripe, Cloudflare, Anthropic, scanned for security-flavored keywords
The first three sources are deterministic. The fourth is fuzzy. To stop fuzzy from torching my budget I do static pre-filtering first, then hit the LLM only on the shortlist:
// 967 npm packages, 50+ NVD entries per week, dozens of blog posts.
// Filter to ~10 items before spending a single token.
const pkgSet = new Set(packages.map(p => p.toLowerCase()));
const nvdRelevant = nvdAdv.filter(adv => {
const lc = `${adv.title} ${adv.description}`.toLowerCase();
for (const pkg of pkgSet) {
if (pkg.length > 4 && lc.includes(pkg)) return true;
}
return false;
});
const all = [...npmAuditAdv, ...githubAdv, ...nvdRelevant, ...vendorAdv];
const shortlist = unique(all).slice(0, 20);
Then Claude Haiku (the cheap model) classifies each item:
async function classifyAdvisory(adv: AdvisorySignal) {
const response = await invokeLLM({
messages: [{
role: "user",
content: `Assess this advisory for our stack (React/tRPC/Drizzle/Clerk/Stripe/Anthropic/Railway).
Source: ${adv.source}
Package: ${adv.packageName ?? "n/a"}
Severity: ${adv.severity}
Title: ${adv.title}
Reply ONLY with JSON:
{"relevant": true|false, "recommendation": "1-2 sentences", "action": "auto-patch"|"manual-review"|"noop"}`
}],
meta: { model: "claude-haiku-4-5-20251001" },
maxTokens: 256,
});
return JSON.parse(extractJSON(response));
}
That's it. ~10 items per week × ~500 tokens per classification × Haiku pricing = ~€0.05 per week. Critical findings trigger an email straight to my inbox; everything else lands in the admin UI as a "proposal".
The whole file is ~480 lines. Half of that is fetching and parsing RSS, because vendor blogs don't bother with consistent feeds.
Component 5: The 7-day soak (the patience)
This is the part I'm proudest of, because it's the part most engineers would skip.
Dependabot opens a PR to dev. CI runs, my auto-merge bot squash-merges it. Now dev is one commit ahead of main. Should I push to production?
Most "auto-merge to main" setups say yes the moment CI passes. That's how you ship a bug that only surfaces in a real browser session, or a Stripe webhook that only fails when an actual invoice.payment_succeeded arrives.
My setup says: not until Muraqib has run seven consecutive nights against dev and all of them are green. Then, and only then, fast-forward dev into main.
- name: Check 7 nights Muraqib-dev-nightly green
run: |
RUNS=$(gh run list \
--workflow="muraqib-dev-nightly.yml" \
--branch=dev --limit=10 \
--json conclusion,createdAt,status)
SEVEN_DAYS_AGO=$(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ)
RECENT=$(echo "$RUNS" | jq --arg c "$SEVEN_DAYS_AGO" \
'[.[] | select(.createdAt >= $c and .status == "completed")]')
TOTAL=$(echo "$RECENT" | jq 'length')
SUCCESS=$(echo "$RECENT" | jq '[.[] | select(.conclusion == "success")] | length')
if [ "$TOTAL" -lt 7 ] || [ "$SUCCESS" -lt "$TOTAL" ]; then
echo "Promotion delayed."
exit 0
fi
The promotion job also reads the diff between main and dev. If the changes touch a high-risk file (server/_core/index.ts, schema, tRPC root) AND any of the commits aren't pure security commits (deps, ci, fix(security)), promotion stops. A human pushed something risky. Humans look at it.
Seven days is arbitrary. It's the smallest number that catches "weird thing that only happens on the third Sunday of the month" without being so long that the queue piles up.
Component 6: Auto-rollback (the emergency brake)
The flight risk in this whole pipeline is: dev was green for seven nights, the merge fires, the deploy goes out, and then something breaks because production has data dev didn't. Maybe a migration deadlocks. Maybe an env var is different. Maybe the cache layer behaves differently under real load.
So the moment main gets a push, this workflow fires:
on:
push:
branches: [main]
jobs:
monitor:
if: "!contains(github.event.head_commit.message, '[skip rollback]')"
steps:
- name: Wait 90s for Railway deploy
run: sleep 90
- name: Poll /api/health for 15 minutes
run: |
FAILS=0
OK=0
DEADLINE=$(($(date +%s) + 900))
while [ "$(date +%s)" -lt "$DEADLINE" ]; do
S=$(curl -s -o /dev/null -w "%{http_code}" "$PROD/api/health")
R=$(curl -s -o /dev/null -w "%{http_code}" "$PROD/")
if [ "$S" = "200" ] && [ "$R" = "200" ]; then
OK=$((OK + 1)); FAILS=0
[ "$OK" -ge 3 ] && exit 0
else
FAILS=$((FAILS + 1)); OK=0
if [ "$FAILS" -ge 3 ]; then
echo "needs_rollback=true" >> $GITHUB_OUTPUT
exit 0
fi
fi
sleep 30
done
- name: Revert HEAD on crash
if: steps.health.outputs.needs_rollback == 'true'
run: |
git revert HEAD --no-edit
git commit --amend -m "auto-revert [skip rollback]"
git push origin main
Three consecutive 5xx within 15 minutes = something broke. Auto-revert. Email me. The [skip rollback] marker on the revert commit prevents an infinite loop where the rollback itself triggers another monitor run.
I've now had this fire once in practice — when a non-security commit (a video-recording feature) introduced a top-level import { chromium } from "playwright" and production couldn't find the package at boot. The autopilot caught it inside a minute and reverted. I read about it in the email, not from a customer.
What the price tag actually is
| Their option | Their cost | What I built |
|---|---|---|
| Snyk Team | €500/month | One TypeScript file |
| Aikido Security | €300-800/month | Six GitHub workflows |
| Wiz | €10K+/month | A dependabot.yml |
| GitHub Advanced Security | €49/user/month | Free GitHub APIs |
| Hiring a security engineer | €80-120K/year | Claude as on-demand CISO |
| My setup | €2.60/year | All of it |
The €2.60 is real. Five cents of Haiku tokens per week × 52 weeks. Everything else is free: Dependabot, GitHub Actions, the NVD REST API, GitHub's Advisory API, npm audit, helmet, isomorphic-dompurify, express-rate-limit.
The price isn't the point. The point is that the time-cost dropped from "we need to hire someone, write an RFP, evaluate four vendors, sign an MSA" to "I described what I wanted, my agent wrote it, I pressed merge."
What it does NOT catch (the honest part)
Don't read this and think you have a force field. You don't. Here's what is still on your shoulders:
- Zero-day exploits. Nobody catches these. By definition, they're not in any feed.
- Targeted attacks. If a determined human picks your platform specifically and spends two weeks on it, autopilot will not save you. You need a pentest for that, which you should buy once a year if you're handling money or health data.
- Social engineering. Your bookkeeper getting a phone call from an AI cloning your voice asking for Stripe access — no amount of helmet config saves you.
- Supply-chain through-routes I don't run audits on. I cover npm. I don't cover Docker base images, OS-level packages, or my Railway runtime. That's another sprint.
- Compliance certifications. SOC 2 / ISO 27001 / HIPAA / NEN 7510 require process + paperwork, not just config. The autopilot helps but doesn't get you certified.
-
A determined customer getting their account hacked elsewhere and reusing the password on yours. Credential stuffing is a thing. Throw in rate-limiting on
/sign-inand breach-password rejection (haveibeenpwned API) for that.
So this stack is "good enough to make you a hard target." It is not "you can stop thinking about security." Anyone who tells you otherwise is selling something.
What you can copy in a weekend
If you're a solo founder or running a small team on a similar stack, here's the minimum-viable version:
- Turn on Dependabot security updates (Settings → Security & analysis → Enable). Free. Five-minute setup. This alone puts you ahead of 70% of websites.
- Add helmet with a real CSP to your Node server. Use the allowlist pattern in my securityRadar.ts if you're on Stripe + Clerk.
- Validate your Stripe webhook signature. Yes, you probably aren't. Yes, that's how 60% of payment fraud against small SaaS happens.
-
Sanitize any
dangerouslySetInnerHTMLwith DOMPurify. Especially if you have user-generated or admin-written content rendered as HTML. - Add an auto-rollback workflow (mine is 80 lines of YAML, paste and adapt the PROD_URL).
-
Wire your CI to gate
dev → mainon at least three consecutive green nights, even if you can't manage seven. Catches 90% of "works on dev fails on prod" surprises.
You don't need an LLM-driven radar to start. But once you have the rest in place, adding ~480 lines of TypeScript for the radar is half a Saturday, and it gives you €500/month of Snyk-shaped value. Worth it.
Why this matters in 2026
Five years ago this stack would have required a small ops team to build and a senior engineer to maintain. Today, the building blocks are free, the wiring is configuration, and the cognitive work — "what should I build, what should I skip, where am I exposed" — can be done in a thinking session with a sufficiently capable model.
The companies that win the next decade aren't the ones with the biggest engineering teams. They're the ones whose solo founders ship infrastructure that used to require a department, and use the time saved on what actually moves the business.
Security is plumbing. Plumbing should not be the reason your company exists. It should be the reason it survives.
Code
The full SecurityRadar lives in server/_core/autoStudio/securityRadar.ts. The four GitHub Actions workflows are in .github/workflows/. Repo is public; clone, fork, steal whatever's useful.
Built for longevityai.nl, a Dutch health AI platform I run solo. The architecture is stack-agnostic — swap React for Vue, Stripe for Mollie, Clerk for Auth0, and the spine still works.
Build it. Ship it. Tell me what you'd change.
Top comments (0)