Ask2DoAsk2Do

Security model

This page is the engineer-facing breakdown of how the security mechanisms work — defense-in-depth layers, signing algorithms, the SQL parser deny-list, recommended DB grants. If you're evaluating Ask2Do for procurement and want to know where your data goes and who sees it, read Data protection.

Threat model: (1) a curious or malicious end-user in the panel, (2) a compromised browser, (3) a compromised cloud orchestrator. Each layer below blocks one or more of those.

Layers, summarized

LayerWhat it blocks
1. JWT authThe browser can't lie about who's logged in or what role they have.
2. Role gateNon-admin/owner users can't drive the assistant.
3. SQL parserCatastrophic statements (DROP, TRUNCATE, bare DELETE, multi-stmt) are rejected before reaching your DB.
4. DB roleEven allowed statements run with whatever permissions you grant the sidecar.
5. Two-phase approvalEvery write is shown to an admin as SQL preview; nothing runs until they click Approve.
6. Audit logTamper-evident record on your DB of every approved or rejected action.

JWT auth (layer 1)

Browsers never hold the long-term tenant key. Instead, your backend exchanges it for a 15-minute JWT signed by cloud's Ed25519 key. The widget includes the JWT in its WebSocket auth frame; cloud verifies the signature on every connect.

Browser ─── (1) GET /api/ask2do/token (your endpoint, your auth)

Your backend ─── (2) POST cloud /auth/token (with tenant key)
                    ←── (3) JWT signed by cloud's Ed25519 key

Widget ─── (4) WebSocket /chat with { type: "auth", jwt }
                    ←── auth_ok if signature valid + role permitted

JWT TTL: 15 minutes. Re-auth happens automatically on the next page load. A leaked JWT only buys an attacker 15 minutes; a leaked tenant key is much worse, which is why only your backend ever holds it.

Role gate (layer 2)

The JWT's payload carries role: "admin" | "owner". Cloud verifies this on every WebSocket message; junior staff can't send a single chat turn even if they were given the script tag.

SQL parser (layer 3)

The sidecar parses every SQL statement the AI proposes and rejects anything in the deny-list before it reaches your DB:

See sidecar/internal/sqlguard for the implementation and full test cases.

DB role grants (layer 4)

The sidecar connects with whatever DB role you give it — usually a least-privileged role. Even when the parser allows an UPDATE, your role's grants ultimately decide what runs:

sql
-- Recommended baseline grants for the sidecar's DB role:
GRANT SELECT ON ALL TABLES IN SCHEMA public TO ask2do_role;
GRANT INSERT ON specific_audit_friendly_tables TO ask2do_role;
GRANT UPDATE ON specific_user_settings_tables TO ask2do_role;
GRANT INSERT ON ask2do_audit TO ask2do_role;
-- NO GRANT for DROP, TRUNCATE, schema modifications, GRANT itself.

Two-phase approval (layer 5)

For any INSERT or UPDATE, the AI emits a SQL preview shown to the admin in the widget. The sidecar holds the proposed SQL in a one-shot in-memory cache; it executes only when the admin clicks Approve. Cancel deletes the cache entry; the audit log gets a rejected row.

Audit log (layer 6)

See audit log docs for schema and sample queries.

Release integrity

Sidecar updates are Ed25519-signed. The cloud's release manifest (a compact JWS) lists every released binary's URL, size, and SHA-256. Each sidecar holds the corresponding public key compiled into the binary at build time, so:

See sidecar/internal/update for the verifier and sidecar/scripts/release/sign-manifest.sh for the cloud-side signing pipeline.

Key rotation

Rotate your tenant key from the portal: /dashboard → pick your tenant → + Issue new key. The new raw key is shown once; copy it to a password manager. Then:

  1. Update your sidecar host's env (ASK2DO_TENANT_KEY) and restart.
  2. Update your backend's env var.
  3. Verify the new key's last_used_at updates in the portal.
  4. Click Revoke on the old key.

The cloud caches verified keys for 60 seconds, so rotations propagate in ≤ 1 minute. For incidents requiring instant cutover, contact hello@ask2do.com — we can flush the cache server-side.

Reporting a vulnerability

Email support@ask2do.com with details. We'll acknowledge within 24 hours. We don't run a formal bug bounty yet, but we appreciate disclosure and credit finders publicly (with permission) when fixes ship.