The core design: your agent never holds the credential
The point of the product is that credentials move out of your prompts, your.env, and your
agent’s context into a server-side vault. Your agent asks Sente for a logged-in session and
receives one of:
- an interactive live view URL (human-watchable, take-over capable),
- a CDP URL to drive with your own Playwright/Puppeteer,
- an exported
storageStateto run locally.
GET /credentials on a connected account returns
403 CREDENTIALS_WRITE_ONLY, permanently. Rotation is re-submitting new credentials. Revoking
a connection stops all use of it in one call (the vault entry is kept so re-connecting re-enables
it); deleting the connection additionally purges the vaulted secrets. See
Sessions for how session handoff works.
At rest
- Credentials and TOTP seeds are encrypted with AES-256-GCM before they touch the database.
- The encryption key is held only in the API/worker environment on our production host — it is an application-level key, not yet a KMS/HSM-held key (that upgrade is on the roadmap and we’ll say so here when it lands, not before).
- For connected accounts, only one code path in the system decrypts credentials: the run controller, at the moment a login/registration run needs them — the public API never returns them. For Sente-created accounts, the generated password is retrievable through the API (it’s your credential; we made it for you), and every read is recorded in the audit log.
During a run (what the models see)
Two different models touch your data, with different exposure:- The browser-driving agent (Anthropic Claude, via API). When it must type your password into a login form, it receives it — the same way a human assistant would have to. Mitigations: the run executes in an isolated remote browser session (a dedicated per-identity browser profile — persistent across that identity’s runs, but never your machine and never shared across identities); the password is registered in a redaction vault before the run starts, so it is scrubbed from logs, step streams, run records, and the activity feed; Anthropic’s API does not train on this traffic.
- The TOTP seed never reaches any model. When a site asks for an authenticator code, the driving agent stops and reports; our server computes the current 30-second code from the vaulted seed and injects only that code. Wrong-seed loops are capped at 3 attempts.
Blast-radius controls
- Per-organization API keys; every identity, registration, and run is org-scoped.
- Per-org caps: identities, outbound sends per day, runs per day — all hard 429s (see Limits).
- Webhook URLs pass an SSRF guard (public addresses only, re-checked at every dispatch).
- A global kill switch can pause all runs platform-wide in one operation.
- Every run leaves a full status timeline + activity record you can audit in the dashboard.
What we don’t have yet (read this before trusting us with production)
- No SOC 2 (yet). Solo-founder company; happy to walk through the posture on a call.
- No KMS-held keys (see above).
- SMS 2FA and CAPTCHAs require a human — a run that hits one blocks and pages you with an interactive live view; Sente never attempts to complete a CAPTCHA. See Runs and human takeover.
- SSO-only accounts (Google/Okta sign-in, passkeys) can’t be connected — there’s no password to vault.
- An exported
storageStateor CDP URL is a bearer credential. Treat it like one: it grants the session it names, and its safekeeping on your side is yours.
Our recommendation for the RBAC-minded
Don’t connect your root/prod account. Create a scoped account or token for the agent in the target app’s own permission system (staging scope, non-destructive prod scope), connect that to Sente, and rotate it on your schedule — re-submitting credentials takes one call and invalidates nothing else. Your model never sees the secret at any point in that loop; your.env stays empty.
Acceptable use: Acceptable use policy. Abuse reports: support@sente.run.