Sonela Security review · one page

Security and read-only validation

This page is for whoever has to approve letting Sonela read your business data: every guarantee below is a property of the code — a grammar, a transaction mode, a column that does not exist.

Where Sonela runs

In the page

One script tag and a widget key — the whole change to your application. The page holds nothing secret: the widget key is public by design, and the tenant identity is bound server-side from a signed token the browser cannot mint. Editing the page's JavaScript reaches no other tenant's rows, and no key of yours. An Origin header is a courtesy, never identity: sessions held to signed-in users open only on a signed voucher outsiders cannot forge — ours do.

In your network — the Sonela Gateway

One small service, on one server of yours, next to the data it reads — never on a staff machine. It dials out to us over port 443, so you open no inbound port and expose nothing to the internet. What it needs to read your data is configured on your side and stays there — run this way there is nothing for us to store, and a row holding null cannot leak. We keep a hash of the gateway key, and both validation and execution run on your side of the firewall.

Read-only, enforced three times

Three independent layers, each sufficient on its own: all three have to fail together before the assistant can change anything.

1

An allowlist grammar, before the query runs

Model-written SQL is refused unless every part of it is explicitly permitted — syntax nobody anticipated is denied by default.

  • Must begin with SELECT. Any semicolon is refused, so the input stays one statement.
  • Every keyword and function must be on the allowlist. WITH, UNION, TABLE x and FOR UPDATE are refused by name.
  • Catalogue access is unreachable: pg_*, information_schema, dblink, the XML table exporters, current_setting.
  • Schema-qualified names, comma-separated FROM lists and parenthesised join groups are refused — each one evades the rewrite.
2

A READ ONLY transaction, while it runs

It runs inside a READ ONLY transaction under a statement timeout of three seconds and a cap of 500 rows. PostgreSQL refuses a write in that mode whatever reached it, and the timeout bounds what any one question can cost you.

3

A rollback, not a commit

The transaction is rolled back rather than committed, whatever it did — a write that somehow executed would not survive the request. All three layers run inside your network.

Tenant isolation by rewrite, not by prompt

Every table reference is replaced with a subquery projecting only the columns you approved and filtering on the tenant column you declared. Isolation never depends on the model behaving, and a table absent from your manifest is rejected. The tenant value is a bound parameter, server-bound from a signed session: the browser cannot assert it, the model never sees it.

What the model wrote

SELECT "Status", count(*) FROM "Orders" GROUP BY "Status"

What actually ran

SELECT "Status", count(*) FROM (SELECT "Id", "PlacedOn", "Status", "Total" FROM "Orders" WHERE "TenantId" = @__ai_tenant AND "IsDeleted" = false) AS "Orders" GROUP BY "Status"

Only approved columns are projected, and a table holding a column named like a secret is withheld whole. The statement is then wrapped in the row limit.

What Sonela can see — and what it cannot

Sonela is a data processor: your content transits our service to one AI provider — yours under your key and DPA, or ours under our agreement and model choice.

Data What actually happens
The question, and the rows that answer it In transit Reach Sonela and one AI provider — yours under your DPA, or ours. Held in memory for one request, never written to our disks.
Stored questions, answers or SQL Never A metering row has counts, latency, tokens, provider and model — and no text column at all.
Written material you upload Stored Procedures and notes you give the assistant are kept in your workspace and sent to that same provider with the question. Workspace-scoped; deleting them removes them.
Transcripts and cached answers Never Transcripts live in the visitor's browser; an answer grounded in query results is uncacheable.
How your data is reached Your side The gateway you run reaches it from inside your network, with a value configured and held there.
Your AI provider key Encrypted Yours: AES-256-GCM, row-bound, never returned. Never On our key: none of yours held.
Write access to your data Never Three layers refuse it, and the last of them discards the transaction rather than committing it.
Your data used to train a model Never We train nothing, and your rows reach one provider and no further.
On request — not shipped today

Need rows that never transit Sonela? Ask about the local data plane — the answer loop, model calls included, runs inside your network.

Ask us for the threat model.

We will send the real one: what we assume, what we deliberately do not defend against, and where the boundaries sit. We hold no security certifications today and would rather say so — what we offer instead is specificity you can check against the code.

hello@sonela.ai sonela.ai