Security model
Hrida CRM is a single-tenant internal tool. Everyone who signs in can see and work every record — there is no per-record permission model. That is a deliberate choice, and it means the boundaries that matter are who gets in and what leaves.
There is no record-level access control. Authorization is entirely ALLOWED_SIGN_IN — who may sign in at all. An empty list fails closed. Treat the workspace like a shared drive of customer data: everyone with an account can read all of it.
Who gets in
| Control | Effect |
|---|---|
ALLOWED_SIGN_IN | The whole authorization model — whole domains or single addresses. Empty means nobody. |
| Google scopes | A Google rep must grant the two read-only Gmail / Calendar scopes to use the CRM. |
| SSO | OIDC only. A row, not a deploy. ALLOWED_SIGN_IN still decides who may have an account. |
| The local admin door | /admin-login — open registration, grants full owner access. Decide whether to leave it reachable. |
| Trusted origins | APP_URL is the credentialed-call allow-list and the post-sign-in redirect allow-list. |
| Cookie prefix | The session cookie is named crm.*, not the library default, so a neighbor on a shared parent domain can't shadow it. |
What the agent may read — and what may leave
The agent may read everything, including full email bodies — a signature block is the best source of a job title there is. The boundary is egress, and it's three rules:
- No customer text in a third-party query. Derived questions only — never a paste of an email into a vendor API.
- Nothing from a mailbox into
/workspace. The sandbox has a different lifetime. - Nothing sensitive logged. Reading is not logging.
The agent carries its own copy of these rules as a prose skill (data-boundaries.md), kept in step with the code.
The sandbox
The agent's shell, file tools and /workspace run with deny-all egress, set on the backend factory so it can't be forgotten per session. Retrieval is unaffected — web fetch runs in the app runtime, web search at the model provider.
The sandbox is never given DATABASE_URL. CRM access is authored tools in the app runtime, not raw database access from a shell. A shell with credentials and a network is exfiltration-shaped even in an internal tool; a shell with neither is a text processor.
Evidence over guessing
The evidence model is a safety property, not just a quality one: no tool accepts a self-graded confidence, weak evidence never writes to a record, and a human value is never overwritten. A confidently wrong fact about a customer is the one failure the whole design exists to prevent.
Pictures are copied through a guarded fetch
Logo and portrait URLs come from a vendor's answer about a domain a rep typed, so a link pointing at 169.254.169.254 is a request forgery from inside the network. Every image fetch goes through one shared SSRF guard. See Enrichment & images.
Reporting
Security issues go through the repo's SECURITY.md, privately — not a public issue.