The Problem

Every security team knows the pain: you run Semgrep, Gitleaks, Trivy, and CodeQL on your codebase — and get buried in 300 findings. Half of them are .env.example placeholder keys, process.env reads flagged as secrets, and package-lock.json dependency noise. Real vulnerabilities drown in false positives.

For small dev teams and startups, this noise doesn't just waste time — it destroys trust in security tooling entirely. Teams stop looking at reports. Real vulnerabilities slip through.

Oculs.io is a multi-tenant B2B SaaS platform that runs 20+ security tools and uses Gemini AI to separate signal from noise — automatically, for every codebase, without per-repo configuration.


What It Does

  • 20+ SAST/DAST tools run in parallel via GitHub Actions (Semgrep, Gitleaks, Trivy, CodeQL, Bearer, Horusec, OWASP ZAP, Nuclei, and more)
  • Two-layer false positive elimination: a rule-based pre-filter kills universal noise (~60% reduction) before any AI token is spent; then Gemini reads the actual file content from GitHub API to make context-aware judgments
  • Cross-tool attack chain detection: Gemini groups findings from different tools into real-world exploit paths — "SSRF reaching an endpoint that exposes a hardcoded AWS key" gets a single correlated group with elevated severity
  • Exploitability scoring: every finding is assessed for real-world exploitability (high/medium/low), not just theoretical CVSS
  • AI auto-fix generation: Gemini generates patch suggestions and remediation steps per finding
  • Multi-tenant B2B architecture: organizations, teams, role-based access, API keys for CI/CD integration

How We Built It

The Zero Stack

The entire platform runs on two services: Vercel and AWS Aurora PostgreSQL Serverless v2. No separate backend, no Lambda, no containers.

All business logic lives inside Next.js 16 Route Handlers deployed to Vercel. Aurora serves as the single source of truth across 12 tables and 8 Postgres ENUMs. GitHub Actions (20+ SAST tools)

│ HMAC-SHA256 signed webhook payload per tool

POST /api/webhook/scan (Vercel Route Handler)

├─► isUniversalFalsePositive() ← rule-based pre-filter

├─► analyzeFindings() ← Gemini AI triage

├─► correlateFindings() ← attack chain detection

├─► bulk INSERT → vulnerabilities (Aurora)

└─► UPDATE scans → completed (Aurora)

Aurora PostgreSQL — Deliberate Schema Design

The vulnerabilities table has 34 columns. Key decisions:

  • fingerprint — stable hash of tool::ruleId::filePath::lineStart — enables cross-scan deduplication and mute carry-forward (a dismissed finding stays dismissed across future scans)
  • correlationGroup — UUID linking findings that form an attack chain; severity is elevated to the worst member
  • exploitability — AI-assessed real-world risk, separate from CVSS
  • triageSeverity vs severity — raw tool severity preserved alongside AI-adjusted severity for full auditability

We use postgres.js with max: 1 connection per serverless invocation — the only safe configuration for Aurora Serverless v2 under concurrent Vercel function execution.

AI Architecture

Three Gemini functions, all lazy (never in the hot webhook path to avoid rate limits):

Function When Output
analyzeFindings() Webhook finalize Triage + CWE + OWASP + exploitability + isFalsePositive
correlateFindings() Post-insert Attack chain groups, severity elevation
generateReport() On-demand (report page) Markdown security summary

ZIP Upload for Teams Without GitHub Integration

For B2B customers who can't connect GitHub (internal repos, air-gapped environments), we built a ZIP upload flow that runs Gemini SAST directly on uploaded source files — no GitHub Actions required. The code files are stored in the scan's JSONB summary column in Aurora, enabling re-scans without re-uploading.


Challenges

Aurora connection management under serverless: Each Vercel function invocation is stateless. Aurora Serverless v2 has connection limits. We solved this with postgres.js max: 1 — one connection per invocation, no pool, clean disconnect. This was counterintuitive but necessary.

Gemini rate limits at webhook scale: When 20 tools send payloads simultaneously, naive AI calls would hit free-tier limits immediately. Solution: the webhook path only stores raw findings. AI triage runs as a post-processing step, and report generation is lazy (triggered only when the user opens the report page).

HMAC-verified multi-tool webhooks: Each of the 20+ tools sends a separate signed payload. The webhook handler validates HMAC-SHA256 signatures, resolves the scan by ID, applies per-tool false positive rules, and handles the "scan complete" event (final payload) separately from per-tool finding events.

False positive pre-filtering: Building a rule-based filter that works across all customer repositories required understanding each tool's failure modes — Gitleaks flags process.env.* reads, Semgrep matches TODO comments as injection sinks, Trivy reports lock file CVEs that aren't real attack vectors. We codified 15+ universal suppression rules before AI even runs.


What We Learned

  • Aurora Serverless v2 is genuinely production-ready for serverless workloads when connection management is done right
  • Gemini's ability to reason about multi-file context (reading actual file content via GitHub API) is what makes AI triage actually useful — not just reformatting tool output
  • The "Zero Stack" architecture (Vercel + Aurora, nothing else) is not a constraint — it's a forcing function that produces cleaner, more maintainable code

Built for the H0: Hack the Zero Stack Hackathon by AWS and Vercel on Devpost.

Live demo: oculs-io.vercel.app
Demo credentials: demo@oculs.io / Oculs.io.2026
Open source: github.com/burakmizan/oculs-io

Built With

  • auth.js
  • awsaurorapostgresql
  • drizzleorm
  • githubactions
  • googlegeminiai
  • next.js
  • postgres.js
  • tailwindcss
  • typescript
  • vercel
Share this project:

Updates