Trust & Security
Last updated: 2026-08-05
Firmloom builds durable institutional memory from your business communications. That means we hold a copy of sensitive data, and we owe you a straight answer to every security question — in writing, on a page you can read without talking to us, and in a one-page summary you can forward to your IT owner or CISO. This page is that answer. Every claim below is something we can defend today; where a capability is on our roadmap rather than shipped, we say so plainly.
The one rule behind everything. No path — no tool, cache, summary, or derived timeline — ever returns a fact whose source message the requester isn't allowed to see. This is enforced by a permission-test suite that runs in CI; a red permission test blocks deploy.
Which suite you are on changes the answers below, so it is stated first. Firmloom runs on Microsoft 365 today: mail, calendar, Microsoft Teams meeting transcripts, and SharePoint and OneDrive documents, connected by one organization-wide administrator consent or by an individual connecting their own mailbox. Google Workspace is not yet available — Firmloom's application has not completed Google's OAuth verification, so no customer can connect it — and when it is, it will be Gmail and Google Drive only: no calendar, no contacts, no meeting transcripts, no mail side panel, and no organization-wide connection at all. On Google each person connects their own mailbox and can disconnect it themselves. Every claim below that names Microsoft 365 is a Microsoft 365 claim, and the sections that differ say so.
Download the one-page security overview — printable, email-ready.
Hosting & data residency
- Firmloom is US-hosted today. Your stored corpus, database, and blobs live in US infrastructure (Neon Postgres, AWS S3 for blobs, hosting/compute on Replit; AI processing at Anthropic and Voyage AI, both US).
- Your data-at-source stays in your source suite's own region — your Microsoft region for Microsoft 365, your Google Workspace region for Google Workspace. Firmloom reads from your own tenant; the ingested copies we build memory from are held in the US.
- For customers in the EU/UK and other regions, this is an international transfer. We make Standard Contractual Clause (SCC) equivalent commitments for that transfer, and we can execute a Data Processing Agreement on request.
- AU/EU data residency is on our roadmap, not shipped. If in-region hosting is a hard requirement for you today, tell us — we would rather lose the deal than misrepresent where your data sits.
Subprocessors
These are the third parties that process customer data, why, and where. New subprocessors are added by notice, not by silent change.
| Subprocessor | Purpose | Data reaching it | Location |
|---|---|---|---|
| Microsoft (Graph API / Entra ID) | Source platform & identity, for a Microsoft 365 customer | OAuth flows; reads mail, calendar, Teams transcripts, SharePoint/OneDrive documents and directory data from your own tenant | Your M365 region |
| Google (Gmail API / Drive API / Admin SDK Directory API) | Source platform & identity, for a Google Workspace customer — not yet available | OAuth flows; reads Gmail content, Drive document content and per-file sharing lists, and (admin connection only) read-only directory and group membership. No calendar, contacts or meeting content. No write scope of any kind | Your Google Workspace region |
| Salesforce (REST / Bulk 2.0 / Pub/Sub APIs) | Source platform, only where you connect an org | OAuth flows; reads the objects and fields listed below from your own Salesforce org. Read-only — no write scope is requested | Your Salesforce org's region |
| Anthropic | AI extraction, classification, summarization, evaluation | Extracted items, plus your own suite's content: M365 — subject/from/date/body, attachment text, document text, calendar events, Teams transcripts; Google — Gmail subject/from/date/body, attachment text, Drive document text, and no calendar or meeting content | US |
| Voyage AI | Embeddings & reranking | Chunk text — mail, attachments and documents on either suite, plus calendar and transcripts on M365; at query time, candidate chunks + query text | US |
| Replit (one Reserved VM) | Hosting & compute | Runs both halves of the product — the web/API service and the ingestion worker — in a single always-on deployment | US |
| Neon | Managed Postgres | All relational data, encrypted at rest by the provider | US |
| AWS S3 (Amazon Web Services) | Blob storage | Stored blob content — raw MIME, attachments, extracted text; encrypted at rest (SSE-S3, AES-256) | US |
| Sentry | Error & performance monitoring | Error metadata and stack traces — no mail content by design | US |
| Resend | Transactional email — reauth nudges, admin and operator alerts, digests | Recipient address and the message body Firmloom composes; no mail content beyond what a digest quotes | US |
May include in future (disclosed as roadmap): AWS Bedrock (the same Anthropic models via AWS — the adapter seam already exists in code) and a payment processor when billing automates.
Two facts worth stating plainly: your search queries are answered from the local index (Postgres full-text + vector search) and are not sent to a large language model — though query text does reach Voyage's reranker. And the assistant you connect over MCP (Claude, ChatGPT) receives tool results under your own assistant-provider terms, not ours.
We do not train on your data
Firmloom does not train AI models on customer data. The AI providers we use are engaged under agreements that do not permit training on our API traffic. We do not sell personal data. This is a contractual commitment, not a preference we could quietly change.
The exact Microsoft Graph permissions we request
We ask for the narrowest set of permissions that lets the product work, and nothing more. Here is the full list with a one-line justification for each.
Organization (application) mode — a tenant admin grants these once for the organization:
| Permission | Why we need it |
|---|---|
Mail.Read |
Read mail from in-scope mailboxes — the corpus the product is built from. |
MailboxSettings.Read |
Read time zone / working hours so timestamps and "who's out" are correct. |
User.Read.All |
Resolve people and the org directory so memory is attributed to the right person. |
GroupMember.Read.All |
Map team membership for team-scoped access and hierarchy. |
Organization.Read.All |
Read the organisation's display name, so the workspace is named after the company rather than a directory id. Reads no mail and no personal data. |
An Exchange Application Access Policy is the Microsoft-side control that narrows Firmloom's
reach to a specific, admin-defined group of mailboxes, and Firmloom recommends configuring one:
without it, an org-wide Mail.Read grant is exactly as broad as it sounds. Firmloom provides a
check that reads back whether an excluded mailbox is genuinely unreadable, so an admin can verify
their policy took effect. Firmloom does not block onboarding on that check — the policy is
enforced by Microsoft, not by Firmloom, and Firmloom does not represent otherwise. Which mailboxes
Firmloom then ingests is separately bounded by the admin's own mailbox selection.
Individual (delegated) mode — a single person connects only their own mailbox:
| Permission | Why we need it |
|---|---|
openid, profile, email |
Sign the individual in and identify their account. |
offline_access |
Obtain the refresh token we store (encrypted) to keep syncing. |
Mail.Read |
Read that individual's mail — the only mailbox in scope. |
MailboxSettings.Read |
Their time zone / working hours. |
User.Read |
Read their own profile. No directory access. |
Also requested at consent time, in every individual connection: Calendars.Read and
Contacts.Read (calendar & contact sync), Sites.Read.All and Files.Read.All
(SharePoint/OneDrive document ingestion). These are scope NAMES on the consent screen, not
switches — a delegated permission never exceeds what the signed-in person can already open, and
SharePoint/OneDrive are not read at all until specific sites or drives are selected. Firmloom does
not describe them as opt-in, because the consent screen asks for them either way.
Google Workspace — the scopes, and the connection model that is genuinely different
Not yet available. No customer can connect Google Workspace to Firmloom today; the application has not completed Google's OAuth verification. This section states the scope in advance so an IT owner can evaluate it before it exists, not after.
| Scope | Why we need it |
|---|---|
openid, .../auth/userinfo.email, .../auth/userinfo.profile |
Sign the person in and resolve which mailbox their connection belongs to. |
https://www.googleapis.com/auth/gmail.readonly |
Read that person's mail — the corpus the product is built from — and count it exactly for the quote before any of it is ingested. |
https://www.googleapis.com/auth/drive.readonly |
Read document content and each file's own sharing list, which is what lets Firmloom refuse to show a document to someone Drive does not already grant access to. |
Requested only on an administrator's connection, never on an ordinary person's:
| Scope | Why we need it |
|---|---|
.../auth/admin.directory.user.readonly |
Know which mailboxes exist in the domain. |
.../auth/admin.directory.group.readonly, .../auth/admin.directory.group.member.readonly |
Resolve who is in a group, so a document shared with a group can be shown to its members and to nobody else. |
Every one of these is a read scope. Firmloom requests no Gmail or Drive write scope of any kind — it sends, replies to, modifies, labels, inserts and deletes nothing, and changes no mailbox setting.
The part worth reading twice: there is no organization-wide connection on Google. Google's equivalent of a tenant-wide grant is a service account with domain-wide delegation — a single private key that can impersonate every user in the domain. Google provides no way to restrict it to a group or an organizational unit, and therefore no way for us to prove to you that it is restricted. Firmloom does not use it and holds no such key. Instead each person connects their own mailbox and can disconnect it themselves: every mailbox Firmloom can read belongs to someone who individually consented, every credential is individually revocable, and revoking one person revokes nothing else.
The cost of that is real and we state it rather than hide it: a Google rollout takes a connect link per person, and an administrator cannot complete it alone. An administrator's directory connection (the three scopes above) connects no mailbox.
Two further honest gaps on this suite, for completeness: there is no Gmail side panel — the Outlook add-in has no Google equivalent and none is planned in this phase, so Google customers work through the assistant over MCP and the web console — and Firmloom reads no reporting hierarchy from Google, so manager-chain scope on that suite exists only where an administrator enters the reporting line in Firmloom by hand.
Salesforce — exactly what we read, and what we never write
Salesforce is a separate, optional Connected Source. Nothing is read from it unless an administrator connects an org from the Firmloom console; connecting is admin-only, because connecting a CRM is a tenant-wide visibility decision.
The grant is read-only. Firmloom requests exactly two OAuth scopes — api and refresh_token
— and requests no write scope, anywhere, ever. api is the scope that covers REST, Bulk 2.0 and
Pub/Sub reads; refresh_token is what keeps the connection alive without re-prompting. The refresh
token is stored sealed with AES-256-GCM.
Eight objects, and only these fields:
| Salesforce object | Fields read |
|---|---|
Account |
Id, Name, Website, ParentId, SystemModstamp |
Contact |
Id, FirstName, LastName, Name, Email, AccountId, ReportsToId, Title, SystemModstamp |
User |
Id, Name, Email, IsActive, SystemModstamp |
Opportunity |
Id, Name, AccountId, Amount, StageName, IsClosed, IsWon, CloseDate, SystemModstamp |
OpportunityContactRole |
Id, OpportunityId, ContactId, Role, IsPrimary, SystemModstamp |
OpportunityHistory |
Id, OpportunityId, StageName, Amount, CreatedDate, SystemModstamp |
Task |
Id, WhoId, WhatId, Subject, ActivityDate, SystemModstamp |
Event |
Id, WhoId, WhatId, Subject, ActivityDate, SystemModstamp |
No other object and no other field is stored. Where Change Data Capture is enabled on the connected org, Salesforce's change events may deliver other changed fields of a record; Firmloom discards those fields without storing them. Contact, User, Task and Event carry personal data, including of people who do not work for you.
Three things worth knowing about how the CRM data behaves once it is in.
- It is labelled as CRM-asserted, not observed. Every fact derived from Salesforce is stamped so that "what the CRM says" and "what the correspondence shows" stay distinguishable — that distinction is the point of the integration, and blurring it would defeat it.
- It follows CRM norms, not mailbox grain — and it is still gated. A CRM-derived row is not
restricted to the mailbox that received a message; that is the whole point of reading a CRM. It is
not tenant-wide either. A seat is shown a CRM fact about an account only where it already has a
visible window onto that account — at least one message it may read that mentions it — and a seat
with no window onto an account is shown no CRM data for it. Every such row is source-labelled
salesforceand carries no mail source, so a CRM row can never surface a mail-derived fact to someone who could not see the underlying mail. - A fuzzy identity match is never silently merged. A Contact or Account that only partly matches an existing record creates a new, CRM-labelled record and queues a review for an admin to confirm or reject by hand.
Disconnecting revokes the connection and purges the staged CRM records for the tenant, audited, and refuses to run while a legal hold is in place. The offboarding purge covers the same tables and counts them on the signed purge certificate.
Ten permission invariants — why a red permission test blocks deploy
Most vendors describe access control as a feature. We treat it as ten permission invariants that are tested in CI over a fixture organization (≈10 users, an org tree, teams, and sensitive mail). If any one of them breaks, the build does not ship — a red permission test blocks deploy. In practice that means a permission regression cannot reach your tenant without first turning a test red and stopping the release.
- Every result is a subset of what you're allowed to see. No tool, cache, or summary bypasses the filter. Caches are stored unfiltered and filtered per reader — a summary computed for a VP can't leak to an individual contributor.
- Sensitive content is invisible in every scope, including hierarchy, except for narrow, per-grantee allowlist matches that still compose with the access gate.
- Hierarchy is strictly downward — the transitive closure of manager edges. Peers are never inferred; upward is never granted.
- Proposed (unconfirmed) teams or merges grant nothing.
- Hierarchy access cannot be switched on for anyone until the mandatory employee-disclosure step is completed (see below) — the admin console blocks the toggle behind it.
- Every MCP tool call writes an audit-log row — with query parameters and source ids — before it returns results, in the same transaction.
- Derived outputs never widen access. Timelines, context summaries, and flagged items only include facts whose source messages pass the requester's filter.
- Depth layers never widen access. Signals, health scores, and similar-entity discovery obey the same rule by their own mechanism; a restricted user's health view provably differs from an admin's.
- Expansion layers never widen access. Person-level aggregates, point-in-time reconstruction, evidence-pack exports, and proactive notifications each stay within the requester's (or recipient's) own scope.
- Memory-quality layers never widen access. Consolidation, profile summaries, and the org brief are assembled at read time under the caller's own scope and audited.
In one sentence: grain is permission, derived form never widens access, and the whole thing is a CI gate rather than a promise.
The AI-action ledger — what your AI saw, proposed, and who approved
As the assistants your team uses move from answering questions to proposing actions, Firmloom keeps
the record of what happened. Every AI-facing action surface writes to one action ledger
(agent_actions): what the AI saw (the retrieval it drew on), what it proposed, and — when a
person went ahead — who approved it, through which gesture (a send or a click), and when.
For a CISO evaluating AI governance, the properties that matter:
- Human approval is structural, not a setting. A database constraint makes it impossible for a
ledger row to reach an approved or executed state without a named approver and an approval time —
enforced at the write path and by a
CHECKin Postgres, and proven by a test that plants a violation and confirms the database rejects it. Firmloom does not act on anyone's behalf; it records proposals and the human authorisation on top of them. - One record across every assistant. The same ledger captures the in-mail drafting surface, the worker-dispatch flow, and the assistant/MCP surface — so "what did our AI propose last quarter, and on whose authority?" has a single, queryable answer rather than one per tool.
- The ledger never widens access. A ledger entry inherits the same permission gate as the content it concerns: you see entries only for accounts you could already query, an operator sees counts only, and the "what was seen" figure is a count with a drill-through to the already-gated audit log — never inline message content. It is a read-only observation surface, tested under the same §6 invariant family as the rest of the product.
- Where to see it. Tenant admins get an "AI Activity" page in the console (a reverse-chronological timeline, filterable, with a per-account view) and a one-line roll-up in the weekly digest.
This is a capability description, not a compliance claim: it gives you the auditability and human-in-the-loop evidence that AI-governance frameworks ask for, but we do not assert conformance with any specific statute or standard on your behalf — see the SOC 2 posture below for what we do and don't claim.
Retention, erasure & the purge certificate
- The memory is independent of your mail client — not of the source item. It survives a person leaving, a thread being archived, and a mailbox going out of scope. It does not survive the item being deleted where it lives: when the source's change feed reports a message or file removed, we remove our copy, and when that was the last copy we erase the item and the facts extracted from it — chunks, extracted decisions/commitments/risks, derived signals, any task brief quoting it, and the stored blobs. A re-enumeration pass catches deletions the feed does not carry. A legal hold suspends all of it. This is set out in Privacy Policy §11.1, which said the opposite until 2026-08-05; the code has behaved this way for far longer, and the policy was the thing that was wrong.
- Ingestion window defaults to 12 months (24 available, configurable) and bounds how far back we ever read. A separate optional rolling-window auto-purge erases content that later ages past the window; it is off by default, and while it is off, content that was in-window when ingested is retained until one of the other mechanisms here removes it. A per-tenant legal hold blocks purges.
- Folder exclusions apply retroactively. Exclude a folder after its mail has been ingested and an hourly sweep removes the copies already held, rather than merely stopping at the next sync.
- Targeted erasure (admin tool): erase by message, conversation, or participant email. It cascades to chunks, flagged items, and blobs; entity mentions are anonymized; every erasure is audit-logged. This supports GDPR right-to-erasure requests.
- Offboarding purge: on offboarding we delete every tenant row and every blob within a 72-hour target, then issue a signed, downloadable purge certificate. This includes the OAuth authorization-server records for your tenant — issued authorization codes and delegated refresh tokens — so no credential we held survives the purge.
- What the purge cannot do — stated on the certificate itself: we cannot revoke your delegated
Microsoft Entra ID consent grant. That grant lives in your directory, and Microsoft exposes
no API that lets an application revoke it or its issued tokens on your behalf. Every certificate
therefore carries a signed
microsoft_graph_consent_revocations: 0entry plus plain-English instructions: to finish de-provisioning, a Global Administrator deletes the Firmloom enterprise application in the Microsoft Entra admin center (Entra ID → Enterprise applications → Firmloom → Properties → Delete). We would rather the certificate say this than let it imply otherwise. - Backups, stated rather than glossed. Our managed database keeps point-in-time recovery history, so for a period after any deletion the data remains recoverable from that history. We do not restore it in the ordinary course — it exists for disaster recovery — and our documented procedure is that a restore which would reinstate erased or purged data has the erasure or purge re-applied before the service is served from it. A purge certificate attests to the live database and the object storage it enumerates, and we would rather say what it does not cover than let it read as more than it is.
Verify a purge certificate yourself
The purge certificate is signed with Ed25519 using a dedicated signing key that is
never the session-auth secret — so you can verify it with only the public key, and rotating our
session auth can't invalidate a certificate we already issued. Each certificate carries its own
publicKey, keyId, and publicKeyFingerprint inline, plus the recipe below.
Current signing key — key id a7f92fef6138f2d4, fingerprint (sha256 of the raw public key) a7f92fef6138f2d461080988e5b38d00480a7a7932ecbbcecd2fa835e35a3423:
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEA2KetqFSr2k1jBoAJfwJk7tlFan8JCsKQIDHnHBEK0gc=
-----END PUBLIC KEY-----
Verification recipe: Reconstruct the signed payload as compact JSON of {tenantId, tableCounts, blobPrefix, blobObjectsDeleted, purgedAt} with object keys sorted at every nesting level and no whitespace, then verify signature (base64) against that UTF-8 byte string using publicKey (Ed25519, SPKI PEM). Node: crypto.verify(null, Buffer.from(payloadJson), publicKeyPem, Buffer.from(signature, 'base64')). OpenSSL: openssl pkeyutl -verify -pubin -inkey publicKey.pem -rawin -in payload.json -sigfile <(base64 -d <<< signature).
Tamper with any table count and verification fails. Verifiable by you, with the public key — not just by us.
SOC 2 posture
We maintain a security evidence trail from day one — the audit log, permission invariants, and change discipline described above are the raw material an audit consumes. We are audit-ready; certification is on our roadmap. For the avoidance of doubt, Firmloom does not claim a SOC 2 certification it has not obtained, and you won't see that claim from us until it's true.
Penetration-test posture
Firmloom's codebase has been through repeated internal adversarial security review — multi-lane reviews covering authentication and session handling, tenant isolation (mandatory tenant scoping, plus row-level security forced on every tenant table — a second layer that binds where the deployment connects under a non-owner database role), MCP token and OAuth flows, cryptography and secrets, ingestion input and SSRF, and API authorization, with findings tracked and closed. A third-party penetration test is on our roadmap; we will state its status honestly rather than imply one we haven't done.
What Firmloom can and cannot see about you
This section is for employees at a company that uses Firmloom. Your employer likely linked you here as part of the disclosure they're required to make before turning on manager-chain access.
If your company uses Firmloom, here is a plain-English account of what it does and doesn't do with your work communications.
What it can see. On Microsoft 365, Firmloom reads work email (and, where your company enables it, calendar, Microsoft Teams meeting transcripts, and SharePoint and OneDrive documents from the sites or drives your administrator selects) from the mailboxes your administrator puts in scope. Where your company connects Salesforce, it also reads — never writes — account, contact, user, opportunity and task/event records from that CRM. If your company is on Google Workspace instead, Firmloom is not yet available to it at all, and when it is it will read only your Gmail and your Google Drive documents — not your Google Calendar, not your contacts, and not any meeting recording or transcript — and only if you connect your own account, which you can disconnect yourself at any time. It builds an organized, searchable memory of business context — commitments, decisions, who's involved in what — so your colleagues and leadership can find answers without re-asking.
What it infers from communication patterns — the complete list. Alongside what messages say, Firmloom computes a set of deterministic signals from communication metadata — timestamps, participants, and thread structure — without reading message content (the computing module is structurally unable to read a body or subject, and that property is enforced and tested in our CI pipeline). Every inferred signal is on this list:
- Reply timing — how quickly each side of a customer or vendor relationship replies, and how that compares to that relationship's own history.
- Contact cadence and silence — how often a relationship normally exchanges mail, and when a gap is unusually long for that relationship (e.g. "day 14 of silence — twice their longest gap this year").
- Thread structure — reply depth, how many people are on a thread, and when people are added to or dropped from CC.
- Attachment activity — counts, sizes, file types, and version churn (e.g.
contract_v7_FINAL) — filenames and metadata only, never file contents. - Relationship shape — how many people on each side are active in a relationship, whether it runs through a single point of contact, and 30/90-day volume trends.
- Outcome patterns — whether a customer account's communication trajectory resembles your company's own previously won, lost, or churned accounts.
Three hard limits, built into the schema rather than policy: (1) all of these signals exist at the relationship/account level only — there is no per-employee score, ranking, or metric row anywhere in the product, and no surface can display one (internal mailboxes appear to administrators only as coverage facts — "which mailboxes are connected"); (2) no emotion, personality, or affect inference of any kind; (3) nothing health-adjacent is ever inferred. These signals answer questions about accounts ("is this customer going quiet?"), never about you ("how fast does this employee reply?" is a question the product cannot answer, by construction).
What it cannot see.
- Not your unsent drafts. A message you haven't sent is never read. Firmloom skips drafts when it lists a mailbox, so an unsent message is never fetched, never stored, never indexed, and never searchable — by your manager, your administrator, or anyone else. That includes the drafts Outlook auto-saves while you type, which you may never have meant to write at all. This is built into how mail is collected, not a setting your employer can turn off. Send the message and it is treated like any other sent mail; leave it unsent and Firmloom never sees it.
- Not your personal life. Sensitive content — including HR, legal, and payroll matters — is
classified and kept out of every query scope, including your manager's. Mailboxes such as
those beginning
hr@,legal@, orpayroll@are excluded by default. - Not sideways or upward. A manager can see business context from the people below them in the reporting chain — never their peers, and never their own manager. Hierarchy access is strictly downward.
- Nothing your colleagues aren't already allowed to see. Every answer, summary, and timeline is filtered to the requester's own access. Firmloom can't be used to surface a message to someone who wouldn't otherwise be permitted to read it.
- It doesn't train AI models on your data, and it doesn't sell it.
Before your manager's chain can query anything about your team, your employer must complete a disclosure step in Firmloom — they have to confirm, in writing, that affected employees were told what leadership can see. Firmloom's software blocks manager-chain access until that confirmation is recorded. If you have questions about what your specific employer has enabled, ask your IT or HR team — they are the controller of your data, and Firmloom acts on their instructions.
Questions
For the full detail, see our Privacy Policy and Terms of Use. For anything not answered here — a Data Processing Agreement, a security questionnaire, or data-residency specifics — contact admin@creatoralliancegroup.com.