Security & control

Automation you control, by construction.

Twin Browser is hardened at every layer — authenticated execution you direct call by call, database-enforced tenant isolation, hashed keys, an encrypted credential vault, and a complete audit log. Control isn't a policy here; it's the architecture.

Controls

Six layers between a goal and an action.

Each control is independent and fails safe — an invalid key, an unreachable credential store, or an unreachable target all stop the run rather than guess.

You direct every run

Nothing runs that you did not ask for. Each call is authenticated with your API key and acts on exactly the target URL you provide — the URL you pass is the instruction. There is no autonomous crawling and no action you did not initiate.

You hold the authorization

You target only the sites you own or are authorized to automate — that responsibility stays with you, where it belongs. Every run stamps the target it acted on into the record, so there is always a clear trail of what was done, and where.

Default-deny RLS isolation

Tenancy is enforced in the database, not just the app. Postgres Row-Level-Security scopes every row to its owner with default-deny policies, so one tenant can never read or drive another tenant's keys, skills, secrets, or run history.

Hashed, per-tenant API keys

The raw API key is shown exactly once, at creation. We store only a hash and metadata — a leaked database never yields a usable key, and revocation fails closed.

Audit log on every call

Every run records its goal, the path taken, the success condition, and the target it acted on. The result is an auditable trail of exactly what each agent did, on which target, and under which key.

Shared skill library — sanitized

When a task succeeds, its sanitized navigation skeleton joins a cross-tenant library so everyone automating the same host compiles faster. Only the structure crosses tenants — host and which UI elements were used. Your field values, credentials, results, and free-text are stripped first, and only your own tenant ever replays your exact path.

Credential vault

Secrets your model never sees.

Store a credential once; reference it by name. Twin fills the value at the keystroke, inside the browser, on your own runs — it never reaches the model, the logs, the audit record, or the shared corpus.

vault.shbash
# Store a credential once — the value goes to the encrypted vault.
curl -X POST https://twin-browser.com/api/v1/secrets \
  -H "Authorization: Bearer ab_live_…" -H "Content-Type: application/json" \
  -d '{ "name": "acme_password", "value": "•••••••••" }'

# Reference it by name in a run — Twin fills it at the keystroke,
# inside the browser, on your own run only.
curl -X POST https://twin-browser.com/api/v1/run \
  -H "Authorization: Bearer ab_live_…" -H "Content-Type: application/json" \
  -d '{ "url": "https://app.acme.com/login",
        "prompt": "sign in", "secrets": ["acme_password"] }'

# The value never reaches the model, the logs, the audit record,
# or the shared corpus. Only the reference name is ever stored.
The authorization model

The target URL is the authorization.

Twin runs exactly the URL you pass and audits the call. Authorization stays with you, the caller — you target only the sites you own or are authorized to automate. Twin is not a CAPTCHA-bypass or anti-bot-evasion service.

Authorized use, plainly

First-party apps, operator-approved automation, internal RPA, accessibility, and authorized testing. Auth, billing, and audit logging run on every call. See the acceptable-use policy for the full boundary.

Security posture

What's enforced, and how it fails safe

Each layer is independent. When something is wrong — an invalid key, an unreachable vault, a cross-tenant read — the system stops or returns nothing rather than guessing.

LayerControlHow it fails safe
Tenant isolationPostgres default-deny Row-Level-Security on every tableA cross-tenant read returns nothing — isolation is in the database, not the app.
API keysPer-tenant keys, shown once, stored only as a hashA leaked database yields no usable key; revocation fails closed.
CredentialsEncrypted vault, referenced by name, filled at run timeThe value is never returned, logged, or added to the shared corpus.
AuditAppend-only log on every callEvery run is attributable to a key and the exact target it acted on.
AuthorizationThe target URL is the authorization signalThe run records the target; authorization stays with you, the caller.
Data handlingField values stripped before anything crosses tenantsOnly the sanitized navigation structure is ever shared.
Shared skill library

The structure is shared. Your data never is.

Twin Browser gets faster the more it is used. When a task succeeds on a host, the path it learned is sanitized into a reusable skeleton and added to a library other tenants can build on — and you build on theirs. Here is exactly where the line sits.

What is shared

  • • The host (e.g. app.example.com) the skill was compiled for.
  • • The ordered structure of the run — which kinds of elements were used (a textbox named “Email”, a button named “Sign in”) and the navigation between them.
  • • A short description of the intent the skill accomplishes.

What is never shared

  • • Any value you or your agent typed — search terms, names, emails, IDs, amounts.
  • • Credentials and secrets. These live in your vault as named references and are filled only at run time, on your own runs.
  • • Run results, page content, screenshots, or anything the automation read.
  • • Your tenant identity and your exact compiled path — only you ever blind-replay your own skill. Other tenants can only adapt the sanitized skeleton, re-grounding every value from their own vault.

Sharing is intrinsic to how the cache compounds across every host the network automates. If your engagement requires that a host's automation structure stay private to your tenant, contact us and we will scope it out of the shared library.

FAQ

Security, answered

How is one tenant isolated from another?
Isolation is enforced in Postgres with default-deny Row-Level-Security policies on every table — keys, skills, secrets, and run history are all scoped to their owning tenant. A query that reaches across tenants returns nothing, so a bug in the application layer cannot leak another tenant’s data.
Do my credentials ever reach the model?
No. Secrets live in an encrypted vault and are referenced by name. The value is injected at the keystroke inside the browser, on your own runs only — it never reaches the model’s context, the logs, the audit record, or the shared skill corpus. Only the reference name is stored.
What is the authorization model?
The target URL you pass is the authorization signal — Twin runs exactly that URL and audits the call. Authorization stays with you, the caller: you target only sites you own or are authorized to automate (first-party apps, operator-approved automation, internal RPA, accessibility, authorized testing). Twin is not a CAPTCHA-bypass or anti-bot-evasion service.
What gets logged on each call?
Every run writes an append-only audit record: the goal, the path taken, the success condition, the target it acted on, and the key it ran under. That makes every action attributable and reviewable, without ever capturing your secret values.
What crosses tenants in the shared skill library?
Only the sanitized navigation skeleton — the host and which kinds of UI elements were used. Field values, credentials, results, page content, and your exact compiled path never cross tenants. Other tenants can adapt the sanitized structure, re-grounding every value from their own vault; only you blind-replay your own skill.

Built for authenticated execution.

Every run is authenticated to a tenant and directed by you. Every key is scoped. Every action is logged. Security by architecture, not by policy.