Skip to main content
友田 陽大
Vibe coding: shipping AI-generated code safely
セキュリティ
バイブコーディング
AI駆動開発
Next.js
Supabase

A security checklist for solo dev — the bare minimum before release (all free)

A pre-release security checklist for solo developers with no time and no budget. It walks how to mechanically close out secrets, dependency vulnerabilities, authorization (RLS), and input validation with all-free tools — Secret scanning, Dependabot, npx @aegiskit/cli scan, /aegis/rls-checker, and more.

Published
Reading time
11 min read
Author
友田 陽大
Share

Let me state the conclusion first. The key to defending security in solo dev is to "let all-free tools mechanize the horizontal controls (measures that apply uniformly across the app) and concentrate yourself only on the vertical risk (authorization / RLS design)." In one-person development with no budget, no time, and no reviewer, measures that rely on your attention will always spring a leak. So let the machine stand guard over what can be delegated to it with a single command, and spend your own time only on the design that only a human can judge — this is the only way to fight that scales.

Working solo × generative AI (Claude Code), I've built a B2B SaaS that won the Minister of Economy, Trade and Industry Award and a payment platform with zero double-charges in production. So I can say this with confidence — for all the speed AI gives you in building, left alone, vulnerabilities pile up at the same speed. But don't worry. The holes you need to close before release in solo dev almost all show up in "fixed places," so you can run through them with all-free tools — one hour the first time, automatic from then on. This article is that practical checklist.


1. Solo dev especially should "let the machine stand guard" — split horizontal and vertical

Security measures split into two kinds of a different nature. This line is the whole strategy for solo dev.

Horizontal controlsVertical risk
What it isMeasures that apply uniformly across the appDepends on the app-specific "who owns what"
ExamplesSecrets, dependency vulnerabilities, headers, input validationAuthorization / IDOR, RLS design, tenant isolation, business logic
Who can fix itThe tool (can be mechanized for free)You (closes only through design and review)
Solo-dev policyAutomate with one command, then don't think about itPour your time here

Solo-dev failures come from mixing these two and "looking at everything by sheer willpower." Try to do even the horizontal controls by hand and you burn out and leak, leaving no concentration for the vertical risk (authorization) that really deserves your head. What can be left to the machine, to the machine; only what only a human can do, to the human. The big picture from the client's perspective is covered in Vulnerability assessment of AI-generated code (close it in four layers) and Taking AI-built code to production (hardening). This article distills that thinking into a practical, free-tools-only procedure for the solo developer who builds.


2. The pre-release checklist (in priority order, all free)

First, the overview. From the top down, ordered by damage size × ease of mechanization.

#ItemWhat it preventsFree toolsFirst time
1Don't leak secretsPublishing keys/tokens to the whole world.gitignore / GitHub Secret scanning / npx @aegiskit/cli scan15 min
2Known dependency vulnerabilitiesLeaving known CVEs unaddressedDependabot / npm audit10 min
3Authorization (vertical risk)Reading/writing others' data (IDOR)/aegis/rls-checker / npx @aegiskit/cli scan20 min
4Validate input at the boundaryInjection / malformed dataZod / npx @aegiskit/cli init10 min
5Stop recurrence in CIA once-fixed hole coming backGitHub Actions (Aegis / Dependabot)10 min

1, 2, and 4 are entirely horizontal (the machine's job). 3 is the only vertical one (your job), and here alone the tool can go no further than "detect and warn." Below, we close them out one at a time.


3. Don't leak secrets (most frequent, worst)

This is the one with the largest damage and, on top of that, the one that happens most often. The moment a secret key enters the repository, you should assume it's been distributed to the whole world (it stays in the history, so deleting it is too late = always rotate it).

There are three things to do.

  1. Never commit .env*. Put .env* in .gitignore. This alone prevents most accidents.
  2. Understand the NEXT_PUBLIC_ trap. In Next.js, a value with the NEXT_PUBLIC_ prefix gets baked into the client bundle in plaintext at build time. Put a service_role key or an API secret here and it's exposed. The mechanism, the typed env boundary, and how to use server-only are explained with real code in Next.js environment variables and preventing secret leaks — the NEXT_PUBLIC_ trap, so I won't repeat them here. It's a must-read even for solo dev.
  3. Let the machine watch. GitHub's Secret scanning runs free and automatically for public repositories, detecting and warning on credentials that slipped in (GitHub Docs). In addition, npx @aegiskit/cli scan catches hardcoded keys/tokens and the "NEXT_PUBLIC_ × secret key" combination on shape (pattern) alone.
# インストール不要。いまのプロジェクトを静的解析する
npx @aegiskit/cli scan

One honest scope note. What the tool can mechanize is detecting "that a secret slipped in." The judgment of "whether that value may be public" is human design that depends on the app's meaning, and it can't be automated. In other words, you can stop the slip-in, but you can't decide whether it may be public.


4. Don't leave known dependency vulnerabilities unaddressed

Even if the code you wrote is perfect, if a dependency library has a known hole, you'll be stabbed through it. This too is entirely the machine's job.

  • Enable Dependabot (free). Enable Dependabot alerts in the repository settings and it notifies you of vulnerable dependencies against the GitHub Advisory Database and automatically opens PRs to the fixed versions (GitHub Docs). Keeping "dependencies up to date" by hand in solo dev is unrealistic, so put it in first. The practicalities of setup and operation are covered in The Dependabot practical adoption guide and Managing vulnerabilities with Dependabot.
  • For a quick local check, npm audit. Even just running it once before you commit reduces the number of known CVEs you bring in.
# 既知脆弱性のある依存を即席で確認
npm audit --omit=dev

As a further trap specific to the AI era, there's "slopsquatting," where generative AI suggests a nonexistent package name and an attacker pre-registers that name. Get in the habit of confirming a package's existence and download track record before you npm install (the mechanism and countermeasures are detailed in Vulnerability assessment of AI-generated code).


5. Don't settle authorization with a "UI if-statement" — the one vertical risk

This is the main keep, and the one item free tools won't fix for you. Both AI and humans tend to settle authorization with "show / don't show the button on the screen," but if the API or DB is hit directly, the UI if-statement is meaningless. Broken object-level authorization (IDOR / BOLA) has for years remained the No. 1, most frequent risk on the OWASP API Security Top 10 (OWASP).

5-1. Suspect "authenticates but doesn't authorize"

The most frequent accident pattern is RLS that requires login but doesn't scope "who owns that row." On Supabase, a policy like this is a danger signal.

-- 危険:ログインさえしていれば「全ユーザーの全行」が読める
create policy "read" on notes
  for select to authenticated
  using ( true );

-- 正しい:自分が所有する行だけに絞る
create policy "read own" on notes
  for select to authenticated
  using ( auth.uid() = user_id );

USING (true) is the correct choice if that table truly is meant to be public (anyone may read it). The problem is writing it on a table of private data. The distinction that "authentication" and "authorization" are different things is explained in detail in Supabase RLS: authenticated and authorized are different.

This isn't a hypothetical worry. In a primary survey of 1,000 public Supabase apps, about 9.2% of the apps that had RLS had a policy that "authenticates but doesn't scope rows to the owner" (a lower bound, since it's a public-repository sample; un-scoped by owner doesn't mean instantly vulnerable — it needs confirmation). The method and the actual data are in the Supabase RLS security field study. And a case where an app was published with RLS unconfigured and others' data got read and written without authentication is actually registered as a CVE (CVE-2025-48757, CVSS 9.3 CRITICAL).

5-2. Machine-detect mistakes of "shape" for free

The correctness of meaning can be judged only by a human, but mistakes of "shape" can be machine-detected for free. /aegis/rls-checker and npx @aegiskit/cli scan read Supabase's migrations/**.sql and warn on the following.

  • Tables with RLS unconfigured
  • Unconditional USING (true) (OK if publicly intended, otherwise needs fixing)
  • A missing WITH CHECK (readable, but the ownership check on the write side is absent)
  • A SECURITY DEFINER function that doesn't pin search_path (a breeding ground for privilege escalation)
-- SECURITY DEFINER 関数は search_path を必ず固定する
create function public.get_my_data()
returns setof notes
language sql
security definer
set search_path = ''          -- ← これが無いと path 経由で乗っ取られうる
as $$ select * from public.notes where user_id = auth.uid() $$;

5-3. Where you keep service_role becomes the "defensive boundary"

Supabase's service_role key runs with PostgreSQL's BYPASSRLS and ignores RLS entirely (Supabase Docs). In other words, the moment you leak this key to the client or the edge, however carefully you wrote your RLS, it's all void. It means the defensive boundary moves to "where the key is kept." Treat service_role as a server-only secret and protect it together with the secret hygiene from Section 3.

This is the one place that "a tool won't close," so it's the point the solo developer should think hardest about. /aegis/rls-checker goes as far as warning on suspicious spots — closing it is your design judgment.


6. Validate input at the boundary

Data that comes from outside (forms, APIs, queries) is all validated at the boundary on the assumption that it "might be adversarial input." Here we're back to horizontal (mechanizable).

  • Boundary type-validation with Zod. At the entrance of a Route Handler or Server Action, always parse external input with Zod before using it. Don't wave it through just because "it worked."
  • Runtime hardening in one command. npx @aegiskit/cli init adds security headers / CSP, rate limiting, CSRF, and a typed env boundary all at once as a single middleware. Rather than hand-writing them every time in solo dev, put it in first and solidify the foundation — that's faster.
# ヘッダー/CSP・レート制限・CSRF・型付きenv境界をミドルウェアで導入
npx @aegiskit/cli init

7. Stop recurrence in CI (don't let the checklist end at "once")

The measures so far will always rot if you do them once and call it done. Every time you have AI add a feature, a new hole gets in, so the checks only deliver value once they're "automatic on every push." Even in solo dev, don't skip this.

  • Add Aegis's CI step (aegis ci) to GitHub Actions, and only high-confidence detections stop the build, with the SARIF left in GitHub code scanning (a design that doesn't break the build on false positives).
  • Dependabot and Secret scanning keep working on every push from the moment you enable them.

The idea itself of "running the same quality gate through the machine every time" is covered in Quality gates for AI-driven development (CI, types, tests, security), and how to proceed so that even handing large-scale implementation to AI doesn't break, in Spec-driven development × Claude Code. Don't slow the generation, but slot one layer of verification in before shipping — this is the only form that keeps quality even for one person.


8. Honest scope — the remainder free tools "don't close"

Finally, the most important caveat. "I added all the free tools, so it's secure" is the worst kind of complacency. A product that advertises that is, if anything, dangerous; honest tools — npx @aegiskit/cli scan included — state their own limits up front.

  • What free tools automate is horizontal controls (secrets, dependencies, headers, input validation).
  • For vertical risk (authorization / IDOR, RLS design, tenant isolation, business logic), they only detect and warn. Closing it is your design.
  • A clean result means "you haven't stepped on the common traps," not "this code is secure."

Even so, the value of being able to mechanically close the most frequent holes is greatest precisely in solo dev. Because it frees one person's worth of attention from the work the machine can do, so you can concentrate on the genuinely hard judgment (authorization design).


Summary: the one-hour pre-release checklist

  • Put .env* in .gitignore, and never commit secrets (if it leaks, rotate)
  • Enable GitHub Secret scanning (free and automatic for public repos)
  • Enable Dependabot + run npm audit before committing
  • Run npx @aegiskit/cli scan to list missing horizontal controls and suspected vertical risk
  • Check the "shape" of your RLS with /aegis/rls-checker, and verify the intent of each USING(true) one by one
  • Confine the service_role key to server-only
  • Boundary validation with Zod + runtime hardening with npx @aegiskit/cli init
  • Make it an automatic check on every push in CI (aegis ci / Dependabot)

It's all free. Horizontal to the machine, vertical to yourself. Keep just this division and even one person can lift "the demo works" up to "it doesn't leak in production." When you need a design review to actually close the detected vertical risk (authorization / RLS design), start from Aegis's free scan, and if you're short on hands, get in touch.

Frequently asked questions

In solo dev, what should I tackle first, for free?
The top priorities are secrets and dependency vulnerabilities. These two can be fully mechanized, and their damage is the largest. Put `.env` in `.gitignore` and never commit it, enable GitHub's Secret scanning (free and automatic for public repos), enable Dependabot (free), and run `npx @aegiskit/cli scan` once. That's 30 minutes the first time, and automatic from then on.
If I add all the free tools, does my app become secure?
No. A tool that says so is, if anything, dangerous. What free tools can automate is 'horizontal controls' — measures that apply uniformly across the app, like secrets, dependencies, headers, and input validation. For 'vertical risk' such as authorization and RLS design, the right answer exists only in your data model, and the tool only detects and warns. Closing it is your design judgment.
How far can I check authorization (RLS) for free?
Mistakes of 'shape' can be machine-detected for free. /aegis/rls-checker and `npx @aegiskit/cli scan` read your Supabase migrations and warn on missing RLS, unconditional USING(true), a missing WITH CHECK, and SECURITY DEFINER that doesn't pin search_path. But the correctness of meaning — 'who should own this row' — can be judged only by a human.
Since solo projects don't get targeted, don't I not need to go that far?
The opposite. Most attacks are run indiscriminately by bots, not humans, and don't care about scale. Even in the primary survey of public Supabase apps, apps with authentication but missing authorization were not rare. Neglect the one-hour, free measures and you go straight to an accident where others' data is read and written (IDOR).

References

友田

友田 陽大

Developer of a METI Minister's Award–winning product. With TypeScript + Python + AWS, I deliver SaaS, industry DX, and production-grade generative AI (RAG) end to end — from requirements to infrastructure and operations — single-handedly.

That AI-generated code — safe to deploy as-is?

After “it works” comes “it doesn't leak” — scan your project free with one command

Aegis, an MIT-licensed OSS, automates the controls AI tends to skip (headers/CSP, rate limiting, input validation, secrets) and detects-and-warns on vertical risks in authorization and RLS design. The fix plan from `aegis fix --format json` pastes straight into Claude Code or Cursor.

Available for both project-based (contract) and advisory engagements. Start with a free 30-minute consult.

Also worth reading