Security

You're handing us the keys to your app. Here's how we guard them.

Last updated May 30, 2026

Ejector sits in a sensitive spot: it reads your code and, for managed-proxy users, holds the credentials that let agents act as your app. We designed the system so that even we can't casually read those secrets, and so a leaked API key can never unlock anyone else's. This page is the honest, technical account of how.

The short version
  • Secrets encrypted with AES-256-GCM, decrypted only in memory at the instant a proxied call runs — never logged, never sent back to the browser.
  • API keys are stored only as hashes. A key resolves credentials through a hash-scoped database routine, so it can only ever unlock the credentials it owns.
  • Capture is gated behind domain ownershipand every tenant is isolated by row-level security — you can only target apps you've proven you control.

01Architecture at a glance

The system is split so that each part has the least access it needs to do its job:

  • Web app & proxy (Vercel) — serves the dashboard, specs, MCP, and the public agent-facing proxy API.
  • Analysis worker (Railway) — an isolated container that does the heavy work, including headless-browser network capture. It's reachable only with a shared WORKER_SECRET, never directly by agents.
  • Data & auth (Supabase) — Postgres with row-level security plus managed authentication.

Agents only ever talk to the public proxy at ejector.dev. The worker and database are internal and aren't exposed to them.

02How we protect your secrets

Server-side credentials you add for the managed proxy are the most sensitive data we hold, and they get the strongest handling:

  • Encrypted at rest with AES-256-GCM. Ciphertext lives in the database; the encryption key does not.
  • Write-only from the UI. Once saved, a secret is never returned to your browser — the dashboard shows only whether it's set, never the value.
  • Decrypted only in memory, for the single proxied request that needs it, then discarded.
  • Never logged. Our request and metering logs record what endpoint ran and its status — never secret values or full payloads.

03API keys & tenant isolation

Your Ejector API keys are shown once, at creation, and then stored only as a hash — we can't recover the original. When an agent presents a key, the proxy resolves the right credentials through a SECURITY DEFINERdatabase routine keyed on that hash. The practical effect: a key can only ever unlock the credentials that belong to it, and a leaked key can never reach another customer's data. Underneath, row-level securityin Postgres enforces that every query is scoped to its owner — isolation isn't left to application code.

04Your source code

We don't keep it. When you connect a repo, the worker pulls a temporary snapshot, runs the analysis, and deletes the snapshot — we retain only the generated spec. There's no long-lived checkout of your code on our infrastructure. Private repos are read with a scoped, encrypted token you can revoke at any time.

05Authorization: you can only eject what you own

Generating an API from a live site's network traffic is gated behind domain-ownership verification: you prove control of the domain via a DNS TXT record or a well-known file before capture is allowed. This is a deliberate guardrail — it stops Ejector from being pointed at apps you don't control.

06Capture credentials

If you capture an authenticated app by supplying a login, those credentials are used in memory only, for that one capture run, to drive the headless browser. They're never written to disk or stored in our database.

07Transport, auth & payments

  • TLS everywhere. All traffic to the dashboard, API, and proxy is encrypted in transit (HTTPS).
  • Managed authentication via Supabase Auth, with optional GitHub OAuth scoped to read access. We never store your password.
  • Payments run through Stripe. Card data goes straight to Stripe — we never see or store it, which keeps card handling out of our systems entirely.

08Infrastructure & least privilege

We build on managed providers (Supabase, Vercel, Railway, Stripe) that maintain their own security programs and certifications, and we keep our own footprint minimal: the analysis worker is secret-gated and not publicly callable for analysis, internal service keys are scoped, and components only hold the access they need.

09What you can do

  • Scope credentials tightly — give the proxy the narrowest API keys that still let your agents do their job.
  • Rotate or revoke Ejector API keys and connected tokens anytime from Settings.
  • Self-host for maximum control — run the proxy yourself or use the direct auth patch so no secrets ever leave your infrastructure.
  • Review activity — watch exactly what your agents called from your dashboard.

10Responsible disclosure

We welcome reports from security researchers. If you believe you've found a vulnerability, email security@ejector.devwith steps to reproduce. Please give us a reasonable window to fix it before disclosing, and avoid accessing other users' data or degrading the service while testing — we won't pursue good-faith research that respects those bounds.