Security

What Ritla can reach, and what it keeps

Ritla renders your site in a browser and writes down what it saw. That is a small amount of access and it is still access, so here is the shape of it.

Your data is separated by row, and by grant
Every table a customer touches has row-level security on, and every policy terminates in the same membership check — there is no always-true policy on anything customer-shaped. On top of that, `authenticated` holds a write grant on exactly three columns in the whole database: a workspace name, a project name and a project URL. A row policy authorises rows and can never authorise columns, so the two together are the gate rather than one doing both jobs.
The scanner cannot be pointed at your network
Every URL is resolved before it is fetched and every resolved address must be public. The classifier handles the forms that usually get missed — IPv4-mapped, 6to4, Teredo and NAT64 addresses, unparseable literals, non-standard ports — and a redirect is not followed blindly: the scanner refuses redirects outright at the robots check and re-resolves the address on every navigation, so a host that answers publicly once cannot point the second request inward.
Screenshots are private and they expire
Evidence images live in a private bucket with no public read. A report renders them through URLs signed for one hour, so a link you forward stops working rather than becoming a permanent window into your site. How long the images are kept is a property of your plan, and the findings, scores and fix guidance are never deleted — only the pictures age out.
The browser that renders your site is not privileged
Scans run in a container as an unprivileged user with the browser sandbox on, downloads refused and pop-ups reaped. It is a rendering engine with no credentials of yours: Ritla never asks for a login to your site, and a scan is exactly what an anonymous visitor could do.
Nothing your site sends us is executed as markup
A report is full of strings your page chose — selectors, text, attribute values — and every one of them is escaped where it is rendered, with Arabic wrapped for bidirectional isolation so it cannot reorder the sentence around it. Uploaded SVG is not sanitised by pattern-matching: it is parsed and rebuilt from an allow-list, at upload and again at render.
Staff access is a row in a table, and it fails closed
Whether someone is staff is answered by a database policy reading their own session, not by an environment variable or a list in code. A lookup that errors is treated as "not staff" and logged, because a failing check that quietly grants access is the one failure mode worth designing against. Every staff action against a customer's account is recorded before it runs, not after.
What we do not have
No certifications, no penetration test, no security questionnaire on file. Ritla is early, and a page like this earns nothing by implying otherwise. If you need a document for procurement, write and we will tell you plainly what exists.

Found something wrong with any of this? Write to hello@ritla.app. There is no bug bounty and there is a person reading that address.