メインコンテンツへスキップ
友田 陽大

Open Source · MIT · @aegiskit

Aegis — defense-in-depth security for Next.js / Supabase, in one middleware file

An open-source toolkit that automates the controls fast-shipping developers (and AI coding agents) miss. It owns the horizontal controls — security headers/CSP, rate limiting, input validation, CSRF, secrets hygiene — and detects and warns on the vertical risks a library cannot fix for you (broken authorization/IDOR, Supabase RLS design mistakes).

npx @aegiskit/cli scan

No install, no config. It statically analyzes your current project.

It does not “completely protect” anything. No tool can, and any product that claims to is dangerous. Aegis complements secure design — it does not replace it.

Why it exists

“It works in the demo” and “it doesn’t leak in production” are different things

Generative AI writes happy-path code astonishingly fast. But production is decided by how it behaves on malformed input, concurrent access, and a perfectly valid request that points at someone else’s ID. Ship without that and it leaks. This isn’t opinion — it’s the public record.

We dug into this “IDOR that opens outside RLS,” from vulnerable to fixed code, with the detection rules on GitHub.

See the detection rules

What Aegis covers (honestly)

The “horizontal” it automates, and the “vertical” it cannot

Security splits into horizontal controls that apply uniformly across an app, and vertical risks that depend on your app-specific “who owns what.” A library can own the former; it cannot own the latter. Aegis does not blur that line.

Horizontal controls

Automated by Aegis

  • Security headers / Content-Security-Policy (nonce-aware)
  • Rate limiting that actually works on serverless (atomic store, Upstash Redis support)
  • CSRF / Origin verification
  • A typed env boundary (no direct `process.env` access)
  • Input validation at the boundary (Zod) and secure defaults
  • Hard-coded secret detection (committed keys & tokens)

Vertical risks

Aegis only detects & warns (the fix is your design)

  • Broken authorization / IDOR & BOLA (point at someone else’s ID, touch their data)
  • Supabase RLS design mistakes (RLS-off tables, service_role bypass, missing WITH CHECK)
  • Business-logic flaws (abusing quantity, price, state transitions)
  • Privilege escalation & cross-tenant access

These are not “install a product and you’re covered” risks. A WAF or headers can’t stop them — the attack is a valid request with correct auth and a correct shape. Closing them takes design and review.

The Aegis detection pipelineCode and SQL are detected as a “suspicion” by static analysis (SAST), promoted to “confirmation” by dynamic checks (DAST), and in CI only high-confidence findings stop the build. Vertical risks a library cannot fix — authorization/IDOR, RLS design — stay detect-and-warn and branch to a security audit that closes them with design and implementation.InputCode · SQLmigrationsStatic (SAST)Detect suspiciontaint · RLS checkDynamic (DAST)Promote to confirmednon-destructive probeCI / SARIFHigh-confidence onlyblock the buildcorrelateAuthorization / IDOR · RLS design · tenant isolation= a library cannot fix (detect & warn only)Closed by auditdesign + build
Static = suspicion, dynamic = confirmation. CI blocks high-confidence only; vertical risks are closed by audit.

What it does

Detect, fix, and keep guarding in CI

Dataflow analysis beyond syntax matching, plus verification of the authorization boundary written in SQL. It suspects statically, confirms dynamically, and auto-fixes only what is provably safe.

  • Static analysis (taint / dataflow)

    Tracks injection classes that syntax matching can’t see, following dataflow within a function. It flags the path where tainted input reaches a dangerous sink without passing a valid sanitizer — with a source→sink trace.

    • SQL injection · SSRF · path traversal · open redirect · DOM XSS
    • Sanitizer validity is judged per sink (URL-safe ≠ SQL-safe)
    • Tainted input with no ownership scope = IDOR detection (authz/idor-tainted-scope)
  • Supabase RLS / SQL verification

    Verifies the authorization boundary written in SQL — where a TypeScript scanner is structurally blind. It reads `supabase/migrations/**.sql` and flags RLS-off tables, missing WITH CHECK, unconditional true, over-broad anon grants, and SECURITY DEFINER functions without a pinned search_path.

    • Correlates weak-RLS tables with the non-admin client code that queries them as a confirmed exposure
    • Designed to report 0 on a correct production RLS design (real risk, not noise)
    • It verifies RLS — it does not replace design or review
  • Safe auto-fixes + agent integration

    Applies only provably-safe transforms (e.g. wrapping a route handler in secureRoute) and presents anything needing human judgment as copy-pasteable steps. It never claims to have fixed what it cannot fix.

    • `aegis fix` previews safe diffs; `--write` applies them (review with git diff)
    • `--format json` makes the plan machine-readable to hand to a coding agent
  • Runtime hardening (middleware)

    Drops in the controls a library can correctly own, as edge-safe primitives. Add headers/CSP, rate limiting, CSRF, and a typed env boundary with one middleware file and one env module.

    • @aegiskit/core is runtime-agnostic (Node / Edge / Browser)
    • Fail-secure: on ambiguity or error it errs safe (never emits an unsafe header)
  • Dynamic analysis (DAST) + SAST↔DAST correlation

    Static is a “suspicion,” dynamic is “confirmation.” It sends safe, scoped, non-destructive HTTP to an app you own and promotes anything reproduced at runtime to build-blocking.

    • Reflected XSS · open redirect · SQLi (boolean/error inference) · SSRF (OOB canary)
    • With test identities supplied, it also checks missing-auth / IDOR (@aegiskit/dast)
    • Safe by default: localhost-only, scope-locked, request-budgeted
  • CI integration (SARIF / blocks high-confidence only)

    Only high-confidence findings fail CI, and SARIF uploads to GitHub code scanning. The source→sink dataflow stays as a clickable trace.

    • One-step adoption via a GitHub Action (the `aegis ci` wrapper)
    • Adds teeth without adding noise — it won’t break your build on false positives

Measured precision

We scanned 450 real, public Supabase apps

Of the 445 that ship RLS, 8.1% had a policy that authenticates but does not authorize. A naive detector over-reports this at 19.3% — about 83% of which are false positives. Aegis eliminated every false-positive class against real data and holds precision 1.0 (zero residual false positives).

  • 8.1%have RLS that authenticates but doesn’t scope to the owner
  • 450public apps statically scanned
  • 0residual false positives (precision 1.0)

“Not owner-scoped” ≠ “vulnerable” — some tables are shared on purpose. That’s why the finding is medium, non-blocking, “verify this is intended,” not fear-mongering.

Read the full study

Quickstart

Start with three commands

No install, no config. First `scan` to surface the current state, then `init` to harden the runtime, then `probe` to confirm at runtime.

  1. ScanNo install or config — statically analyzes your current project
    npx @aegiskit/cli scan
  2. Harden runtimeAdds headers/CSP, rate limiting, CSRF, and a typed env boundary via middleware
    npx @aegiskit/cli init
  3. Confirm at runtimeSends safe, non-destructive probes to your app to confirm static findings at runtime
    npx @aegiskit/cli probe http://localhost:3000 --correlate

Add it to CI (SARIF → GitHub code scanning)

Only high-confidence findings fail the build, and the dataflow trace lands in GitHub code scanning as a clickable path.

# .github/workflows/security.yml
name: Security
on: [push, pull_request]
jobs:
  aegis:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write # upload SARIF to the Security tab
    steps:
      - uses: actions/checkout@v4
      - uses: tomodahinata/aegis@main
        with:
          severity: HIGH
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: aegis.sarif

Honest scope — what Aegis does NOT do

The “we installed it, so we’re fine” reflex is exactly what produces the worst security outcomes. So here’s what it can’t do, stated first.

  • It does not prove your authorization is correct. It reads the shape of a policy or implementation, not the meaning of your business rules and data model.
  • Dataflow analysis is intraprocedural (within a function). Flows that cross modules or the framework are missed.
  • It does not replace RLS design, code review, threat modeling, or manual penetration testing. It complements them.
  • A clean run means “you haven’t hit the common traps,” not “this code is safe.”

Even so, mechanically closing the highest-frequency holes is worth a great deal: detection grows teeth, noise stays low, and people focus on the genuinely hard judgment — design and authorization.

FAQ

Frequently asked questions

  • Is Aegis free?

    Yes. It’s MIT-licensed open source, usable right now via `npx @aegiskit/cli`. Scanning, runtime hardening, and CI integration are all free.

  • If I add Aegis, is my app “completely safe”?

    No — a tool that claims so is dangerous (the “we installed it, so we’re fine” reflex produces the worst outcomes). Aegis automates the horizontal controls and only detects and warns on the vertical risks a library can’t fix (authorization/IDOR, business logic). It complements secure design, code review, and manual pentesting — it does not replace them.

  • Can I use it outside Next.js / Supabase?

    The core (@aegiskit/core) is a set of runtime-agnostic primitives — headers/CSP, rate limiting, typed env, and more are generally usable. The Next.js (App Router) adapter and Supabase RLS verification are the parts optimized for those two.

  • Will false positives break my CI?

    By default only high-confidence findings fail CI. It further promotes a static “suspicion” to build-blocking only when a dynamic probe reproduces it — so it stops real risk without adding noise. Across 450 real public Supabase apps, the flagship rule held zero residual false positives (precision 1.0).

  • Does it help review AI-generated code?

    That’s exactly the use case. It mechanically surfaces the injection, RLS, and authorization traps that AI-generated Next.js × Supabase code routinely creates, and `aegis fix --format json` hands a fix plan to your coding agent.

  • How do I fix the authorization/IDOR issues it finds?

    That part is outside a library’s reach — it’s your design decision. How you write RLS, the ownership checks on service_role paths, and tenant isolation must be closed with design and review. If you need hands, I offer that design review and implementation.

Next step

Try the free OSS right now. And if you need a design review to actually close the “vertical risks” it finds, I take that on.

Request a design review

The vertical risks it found — I’ll close them

Authorization/IDOR, Supabase RLS design, and tenant isolation are outside a library’s reach — they’re design decisions. I review authorization on existing Next.js × Supabase apps and design + implement the fixes for what was found.

See the security audit

Spot review from $680 · standard audit from $1,900. Starts with a free 30-min call.

Try it yourself first

Free and open source, right now

No install. Scan your current project with one command. MIT-licensed — modify and use commercially, freely.

npx @aegiskit/cli scan
Star it on GitHub

A paid “Aegis Team” tier is in the works.Join the waitlist