Security & trust
AssemblyWright reads a CRM org you connect, writes deliverables about it, and — only on an instruction from one of your authorized users — changes it. This page describes how that is protected, and, just as deliberately, what we do not yet claim. It may only say what docs/security-posture.md says; when a control changes, this page changes in the same commit.
Running a security review? The questionnaire below answers the standard questions once so you can forward them once. The plain-English privacy notice describes what is stored, where and for how long. The legal documents — Terms, Privacy Policy, DPA, Acceptable Use, Refund Policy — are in force since October 29, 2026.
Forwarding this to a security reviewer? Print this page or save it as a PDF from your browser — it prints on plain white, without the site's navigation, with the address of every outside link written out. If your review needs more than this page, or you have a questionnaire of your own, request access and say so: we answer security reviews and questionnaires directly.
Last reviewed: 2026-10-29.
What we do
Every workspace is isolated at the data layer, in one place. Every tenant-owned table carries a workspace identifier and the filter is applied once, at the ORM, rather than in each feature: reads are rewritten to add the scope, writes are stamped with it, an attempt to write without a scope raises rather than writing an unattributed row, and a read without a scope returns nothing rather than everything. It is proven against a real database — another workspace's row is invisible by query, by count and by direct primary-key lookup — and the live posture is reported by an open endpoint (/api/public-config → "tenancy":"enforcing"), so it is checkable rather than asserted.
Your CRM credentials are encrypted as a whole and never shown back. Connection credentials — a Salesforce private key and client id, a Dynamics client secret, a HubSpot private-app token — are encrypted at rest as one blob, not field by field, and the API returns field names only, never values. Settings are namespaced per workspace and secrets never fall back to a shared value, so one workspace cannot inherit another's org. Volatile token caches are cleared on every connection switch, so a token minted against one org is never replayed against another.
Nothing writes to a production org by itself. The models draft, review and propose. Every write to a connected org — a metadata deploy, a bulk data update, seeded test data — is a separate, role-gated action taken on an instruction from one of your authorized users. The one exception is autonomous mode, which a workspace admin may switch on: it lets the models make changes without a per-change approval only in an org the product has confirmed is a sandbox — a production org, or one it cannot classify, still waits for a person every time, and Dynamics 365 and HubSpot changes always wait for a person. The Acceptable Use Policy leads with the rule that you connect only an org you are authorized to change, sandbox first. A metadata deploy snapshots the pre-deploy state so the components it changed can be restored — the undo refuses to run against any org but the one the change was made in, and it does not remove components the deploy added; a bulk update captures the prior record values before writing; seeded test data carries a removal tracer. Where those rollback payloads live is your choice — our database, or a file in your own org with only a receipt and a checksum kept here — and a capture that cannot be stored under the chosen custody fails the job rather than proceeding without a backup. What rollback cannot undo — the downstream automation your own org ran on a change — the Terms say plainly.
Accounts, roles, and elevated actions. Identity is provided by Clerk (RS256 tokens verified against published keys, issuer and expiry checked) and gates every API route. The paths that answer without a sign-in are: the health and readiness checks, the public configuration and the authentication-readiness probe (each names only what the app already publishes); the client-error beacon; the website's request-access form (which can only add a request to the operator's inbox, is rate-limited per address and per day, and reads nothing back); the payment page (/pay, which loads Paddle's checkout only when a Paddle transaction id is in the address and reads no database); and the public blog (approved articles only, nothing today) — plus the doors an outside system calls, each authorized by a signature or a signed single-use token rather than a sign-in: the two payment-provider webhooks (Paddle, and the unused Stripe adapter), the webhook for a workspace's own Paddle account, the email unsubscribe and bounce addresses, the three social-network sign-in redirects (LinkedIn, X, Threads) and the Salesforce hosted-MCP sign-in redirect. One second credential exists, and it can admit only the platform operator: a per-request token from Evadaroo HQ, our company's own operations console, signed with its key (ES256), bound to a single request, usable once and valid for at most two minutes — and accepted only for an identity the product's own operator rule already admits, and only on the operator's own administration routes. It is off unless configured, and the public configuration says which; it is configured in production. Per-workspace roles — viewer, operator, admin, owner — are built and enforced in one middleware: starting a Build needs the operator rung, and about 120 destructive, cost-bearing or org-touching routes require admin or owner. Role enforcement for a workspace's own users switches on only once self-serve sign-up is restricted to invited people, and today sign-up is public, so it is off (/api/public-config → workspaceRoles): while it is off, a customer's own actions that run work or touch an org — starting a Build, approving a gate, Wright chat, editing Wrights, workflows and the Knowledge Base, connecting or writing to an org — are refused rather than permitted broadly, and only accounts AssemblyWright lists can perform them. A user recorded as a workspace's owner or admin can still export, close (an owner) and reopen it, restore items from its trash and delete them permanently, change its preferences and retention settings, start a subscription and (an owner) manage its members, and an operator can still ask the Guide. Multi-factor sign-in is not enforced by the product and is not switched on at the identity provider for production sign-in.
Spend cannot run away. A per-Build dollar ceiling warns at 80% and pauses for approval rather than running on; a model-call budget per Build pauses and asks rather than cancelling; a durable per-workspace budget brake is computed from recorded usage, not counted in memory; a per-customer AI allowance (US $25 by default, over the customer's whole life, set by the operator) is designed to refuse or pause new Builds, pause running ones and stop the app's AI once it is used up; per-IP rate limiting trusts only the proxy-appended hop; and there is a daily Build cap.
Privileged actions are recorded. An admin audit table records the actor, the trusted client IP, the action and the detail for settings changes, model credentials, CRM connect and disconnect, vault operations, snapshot restores and permanent deletes — and the detail logs what the act concerned and the field names a change touched, never a credential's value (for some non-secret settings, such as a retention period or a custody mode, the new value is recorded). Structured request logs (method, path, status, timing, the signed-in account and workspace — never a body or a token) and capped client crash reports sit alongside it. The web server also writes its own access log, which records each request's full address including any query string: the signed token in a Paddle-signals address is removed before it is written; a token in an email unsubscribe link or the single-use codes in a sign-in redirect are not.
How code reaches production. Every backend module carries a self-test, and the full suite — with a dependency audit and a sweep of every page — must pass on the exact commit before it can be deployed: the production machine deploys only a commit that carries that record, and holds anything else. Deploys refuse a web-server configuration that does not validate, rebuild, check the application and the web server, and automatically roll back and quarantine a bad commit — a path exercised once in production, on 2026-07-21. Database migrations are never auto-applied. Production dependencies are pinned in a lockfile generated from a clean environment, the image installs from that lockfile, and the pins are scanned against the public advisory database with the dated output kept, and the two Node dependency trees (the web build tooling and the iPhone app's build tooling) are audited the same way; an open advisory in what ships fails the gate, so nothing has shipped with one since that rule was added on 2026-09-30.
Watched from outside. Since 2026-10-05 an external uptime service checks the product every five minutes and emails the operator when a check fails. Two of those checks read the answer rather than only the status code: that sign-in can work (the authentication-readiness probe must answer "ok":true) and that workspace isolation is on (the public configuration must answer "tenancy":"enforcing") — because the plain health check answers "the process is up" and knows nothing about either.
Backups: what exists, and what is still being put in place. A backup script exists that dumps the database, checks the dump is complete before it leaves the machine, and records every table's row count beside it, and there is a written disaster-recovery runbook. A restore from such a dump was rehearsed on 2026-08-18 on a separate machine — not yet on the production machine. Scheduled off-server copies of the database to Google Cloud Storage are being set up: the job that makes them was installed on the production machine on 2026-10-12, and on 2026-10-21 the storage bucket it writes to answered an anonymous probe with 401 — it exists — where on 2026-10-09 it answered that it did not. What is not yet confirmed: that a copy has actually landed there on schedule, and a timed restore from one on the production machine. We will claim them here — and any disk-snapshot schedule — only once each is confirmed.
Encrypted in transit. TLS with automatic certificates on every hostname, and HSTS and a standard security-header set on every hostname that serves pages (the two www hostnames only redirect).
Written policies. Access review, incident response, change management, data classification and retention, and vendor management — each describing what actually happens and stating its own gaps. Two of them, data classification and access review, predate workspace isolation and are being brought up to date, and the first access review has not yet been run. Available on request, with that said.
Questionnaire answers
Where is customer data hosted? On Google Cloud in us-central1 (a single virtual machine running the application and PostgreSQL). The browser runner that walks a connected org's screens for UI verification runs on Cloud Run in the same region, only where a workspace switches that feature on, and keeps nothing. Off-server backups, to Google Cloud Storage, are being set up (above). All customer data is stored in the United States; no regional choice is offered. AI requests are processed wherever the model provider that answers them processes them: as of 2026-10-29 the models every default chain uses run in the United States, while two other providers the operator can route a request to can run one outside it (below).
Is data encrypted in transit and at rest? In transit, TLS on every hostname, with HSTS on every one that serves pages. At rest, Google Cloud encrypts the disks and storage; on top of that, credential-shaped values are encrypted at the application layer under a deployment key. Stated limitation: that key lives in the deployment environment on the host — there is no managed key service and no automated rotation procedure, and no confirmed copy of that environment exists off the machine.
How are customers isolated from each other? Row-level isolation enforced at the ORM in one place, proven and reported live (above). Isolation is logical, not physical.
How is authentication handled? Clerk. Self-serve sign-up on Clerk Organizations is switched on and open in production today (/api/public-config → clerkOrgs), which is also why role enforcement for a workspace's own users is off (above); restricting sign-up to invited people is the step that switches it on. There is no SAML and no SCIM. Multi-factor sign-in is not enforced by the product and is not switched on at the identity provider for production sign-in.
What does the AI see, and does it train on our data? The prompt for a stage — your Build request, the org context imported from your connected org, Knowledge Base material, prior deliverables — goes to the model that answers. Which model answers is set by a chain the operator configures and can change; only its entries from providers whose terms do not permit training on inputs, and that are connected (a key held or, for Vertex AI, which takes no key, a Google Cloud project configured for it), are ever called. As of 2026-10-29 every chain the product uses by default starts with Anthropic's Claude, and every Claude call is held to processing in the United States: Claude Sonnet 5.5 for every feature and agent the operator has not given a chain of its own, Claude Opus 5.5 for the architect agents, and Claude Haiku 5.5 for the documentation and writing agents and most of the app's own AI (the workflow builder follows the default chain). Claude is reached over Anthropic's own API under Anthropic's commercial terms; the product adds Anthropic's US-only setting to each request and never calls a Claude model that cannot honour it, and where a newer Claude Opus, Sonnet or Haiku costs no more and can be held to the US, it may call that one instead. Behind Claude in every chain sits Google Vertex AI — Gemini 3.8 Flash, then 3.5 Flash-Lite, in Google's us multi-region, under Google Cloud's enterprise terms, which provide that customer inputs are not used to train Google's models — and Vertex AI also answers a feature the operator routes to it and a Gemini model a workspace picks for a second-opinion or two-approaches stage. The features that call a model directly (the questions asked before a Build, the workflow fit check, the advisors, the Knowledge Agent, Bench routing) use the first usable model of their own chain, or else the first of the default chain (Claude Sonnet 5.5), and try no other model if that call fails. Cloudflare Workers AI and OpenAI are connected and in no default chain: each answers only where the operator routes a feature or agent to it, a workspace picks one of its models for a second-opinion or two-approaches stage, or a workspace's image model is one of its models, and neither is held to the United States — Cloudflare runs a request on its global network and OpenAI in its own processing locations. A picture prompt goes to the image model set for the workspace — Imagen on Vertex AI, in the Google Cloud region the deployment is configured for, unless we (or a workspace admin, once roles are on) name a model of another listed provider; the Imagen model the product names by default was retired by Google on 30 June 2026, so until a current one is set, no picture is generated. A guard in the code enforces the free-tier rule in production: a provider whose terms permit training — Google AI Studio's free tier, Groq, Cerebras, OpenRouter, Mistral, GitHub Models, xAI — is never selected, as the primary model, a failover, a per-feature or per-agent choice, or a saved setting; and if nothing else remains, the call fails rather than falling back. The guard has one deliberate override, a deployment setting we will not set for a deployment serving customers. Google AI Studio's free tier is development-only by written policy and never sees customer data. Outputs may be wrong; review gates and human checkpoints exist so a person decides.
Do the models act on our CRM? Not without an instruction. Every write is a separate, role-gated act on a human instruction (above); the one standing instruction a workspace admin can give is autonomous mode, which the product honours only in an org it has confirmed is a sandbox.
Do you store our passwords or tokens for other services? The CRM credentials you give us, encrypted as described; credentials for other systems you choose to connect — Jira, Confluence, GitHub, Google Docs, Salesforce's hosted MCP servers, and a Profusia access key — encrypted the same way; only if you switch on the Content Desk and connect a social account, the posting token for that account, encrypted the same way, never returned by any interface, and used only to publish a post after a recorded approval; and — only if you connect Paddle to a factory — that factory's Paddle API key and notification secret, encrypted the same way, used only to read your Paddle account and to verify the events it sends (the connection has no write actions). Nothing else. Disconnecting deletes them, and closing a workspace erases every one at once.
What are your backup and recovery arrangements? Partly in place, and stated as such. A backup script that verifies each dump before it leaves the machine and a written recovery runbook exist, and a restore was rehearsed on 2026-08-18 on a separate machine, not yet on production. Scheduled off-server copies are being set up: the job is installed on the production machine (2026-10-12) and the storage bucket exists (probed 2026-10-21); we have not yet confirmed that a copy has landed on schedule, and no restore from one has been timed on production. We will claim them, and any disk snapshots, only once each is confirmed. A deploy that fails its checks rolls itself back automatically — exercised once in production, on 2026-07-21. No uptime commitment is offered.
What is logged, and can we get the logs? The admin audit trail (actor, IP, action, field names) — rotated to the newest 2,000 records per workspace, so keep your own copies if you need a longer archive: once roles are on, a workspace admin reads the newest entries on the Activity page, and an owner or admin can ask us for the trail as kept, which we send within 30 days, once a quarter at most. Request logs and crash reports are operational: the structured request log never records a body or a token; the web server's own access log records full addresses including query strings (above), and neither has a retention limit yet — they are kept until the log files are cleared.
How long is data kept, and how does deletion work? Deliverables, Builds, Knowledge Base entries and imported org context stay until you delete them; deleted items go to a trash with a type-to-confirm permanent delete. Rollback payloads are destroyed after 30 days by default (configurable per workspace), leaving a receipt. Deliverable text can be held in your own org instead of ours, and a retention window and version cap can be set — all off unless you set them. An admin or owner can export the whole workspace in one archive — every current deliverable as Markdown, the Knowledge Base, a list of every Build, and the names of its workflows, Wrights and connections (not credentials, trashed items, earlier versions or the rest of the configuration). An owner can close the whole workspace by typing its name: every credential it holds is erased at once and access ends at once; it stays dormant and reopenable for 30 days (export first — nobody can reach it during the 30 days unless an owner reopens it); after that its rows and memberships are erased, and today a person runs that erasure rather than a scheduled job. Deleting one individual's data is a manual process on request, confirmed in writing; we say so rather than implying a self-service path that does not exist.
Does customer content execute on your servers? No. Deliverables are documents. The only thing that runs against your systems is a deploy or data operation you instructed, through your CRM vendor's own APIs, with a rollback snapshot taken first.
How do we report a vulnerability? security@assemblywright.ai, published at /.well-known/security.txt per RFC 9116. We do not run a paid bounty programme and will not pursue researchers who report in good faith.
Subprocessors (as of 2026-10-29)
| Subprocessor | Purpose | What it can see | Region |
|---|---|---|---|
| Google Cloud Platform | Hosts the application and the database, and will hold the off-server backups once they run. Runs the browser runner (Cloud Run) for UI verification and training-guide capture, only where a workspace switches those on. | Everything stored in the service. The browser runner receives, per walk, the verification plan, a session token for your Salesforce org, and the screenshots and recording it takes of that org's screens; it returns them and is discarded. | us-central1, USA |
| Anthropic — Claude, over Anthropic's own API — the primary AI | AI inference for Build stages, review gates and the app's own AI: first in every default chain (Claude Sonnet 5.5 by default, Opus 5.5 for the architect agents, Haiku 5.5 for documentation, writing and most of the app's own AI); the default model the features calling a model directly fall back to when none of their own chain can be used; and a second-opinion or two-approaches model a workspace may choose | Prompt and response content: Build inputs, org context, generated deliverables. Under Anthropic's commercial terms, inputs are not used to train. | USA — every call is held to US-only processing |
| Google Cloud Vertex AI — serving Google's Gemini models, and Imagen where a Build asks for a picture and Imagen is the workspace's image model | Behind Claude in every default chain (Gemini 3.8 Flash, then 3.5 Flash-Lite), answering whenever Claude cannot; a feature the operator routes to it; and a Gemini model a workspace picks for a second-opinion or two-approaches stage | Prompt and response content, as above; for Imagen, the picture prompt. Does not train on customer inputs. | USA (us multi-region) for Gemini 3.8 Flash and 3.5 Flash-Lite; Imagen and other Vertex models in the region the deployment is configured for |
| Cloudflare Workers AI — connected; in no default chain | AI inference only where the operator routes a feature or agent to it, a second-opinion or two-approaches model a workspace may choose, and a picture prompt where a workspace's image model is one of its models | Prompt and response content, as above. Under its terms, inputs are not used to train. | Cloudflare's global network, which can be outside the USA; no region is set |
| OpenAI — connected; in no default chain | The same | Prompt and response content, as above. Under OpenAI's API terms, inputs are not used to train. | OpenAI's processing locations, per its terms, which can be outside the USA; no region is set |
| Clerk | Authentication and identity, including organization invitation email | Email addresses, sign-in metadata, session tokens | USA |
| Resend — configured in production | Delivering the product's own notifications: a Build finished, a review gate is waiting, your input is needed; Content Desk digests — and, only where a factory switches on a Paddle email response and a person approves each send, that factory's service emails (such as a welcome) to its own customers. One Resend account serves both AssemblyWright and Profusia, so the same operator sees both products' sending records in one dashboard. | The recipient address, the notification's title and detail, and a link back to the Build; for a service email, your customer's address and name and the email your team wrote | USA |
| Apple Push Notification service — only if you use the iPhone app and push is configured | Delivering the same notifications to a phone | The notification's title and detail (never deliverable content, never CRM data), the Build's route, and a device token | Apple's network |
| Google Workspace | Our company mailboxes (legal@, security@, billing@ and hello@assemblywright.ai) | What you send us, and our replies | USA |
| Uiia (Evadaroo & Company, LLC) — the in-app Help assistant, switched off today (since 2026-09-29) | Answering questions asked in the app's Help panel, from help articles we approved, while it is on | While off, nothing is loaded from it and nothing reaches it. While on: the questions you type into Help, and your email address if you ask to be contacted — never deliverables, Build content or CRM data from the product. Its answers would come from AI models on providers' free tiers, whose terms may allow them to use what they are sent to improve their models, so do not type customer data into Help. | Cloudflare's network |
| Evadaroo HQ (Evadaroo & Company, LLC) | Our company's own operations console, on Cloudflare's network; the source of the operator token described above | What the operator console shows — customer and workspace names, counts, usage figures, entitlements and model routing — never workspace content; it can perform the operator's own acts through the product's operator routes, one signed request at a time, each recorded. | Cloudflare's network |
| Cloudflare — DNS only | Answers DNS queries for assemblywright.ai | DNS queries. Our records are not proxied through it, so its DNS service does not see the traffic to the app or the website. Its Workers AI is a separate service, listed above, that receives the AI requests routed to it. | Cloudflare's network |
| Let's Encrypt | TLS certificates | Domain names only | — |
Not subprocessors: Paddle (Paddle.com Market Limited and its affiliates), our reseller and Merchant of Record for paid plans, which processes billing contact, payment and tax details as an independent controller under its own privacy notice, in the UK, the USA and elsewhere — it receives no customer content, payment details go to it and never to us, its own checkout code runs in your browser on /pay, and it is connected in its sandbox today, so a checkout opens a test transaction and takes no real payment (live from the date we begin taking payment); your CRM vendor (Salesforce, Microsoft, HubSpot — your own vendor relationship; we act on it with credentials you supply), and Salesforce's hosted MCP servers reached the same way; Google Docs, Jira, Confluence and GitHub, where you connect them as destinations with credentials you supply; Profusia AI — our company's other product — where you connect your own Profusia workspace with an access key you supply (the deliverables you publish, and the Build request as the description of the collection they land in, go there under your own Profusia terms and its DPA; it is a destination you elect, not a sub-processor of ours); the social networks you connect through the Content Desk (LinkedIn, Bluesky, Mastodon, Threads, Dev.to, X — your own accounts, receiving only a post a person approved); Paddle, when you connect your own Paddle account to a factory — separate from Paddle as our reseller (we read from it with a key you supply and receive the events it sends); Google AI Studio (development only, by written policy); GitHub as the home of the application source (no customer data, no production secrets); the external uptime service (it fetches only our public status addresses and pages).
We give 30 days' notice of a new or replacement subprocessor, as set out in the DPA.
What we don't claim
A security page that lists only strengths tells you nothing, because every security page lists only strengths. Here is the other half.
- No SOC 2, ISO 27001 or HIPAA attestation. None in progress. Deliberate for a product at this stage: the controls above are built and real, and a formal attestation follows a business reason to hold it. If your procurement requires a report, say so — that is exactly the business reason.
- No third-party penetration test. We publish a security contact and welcome researcher reports; we have not commissioned an independent test and do not claim one.
- Isolation is logical, not physical. Customers share infrastructure, separated in software — the same model most multi-tenant SaaS uses.
- Role enforcement for your own users is switched off while sign-up is public, and multi-factor sign-in is neither enforced by the product nor switched on at the identity provider. Restricting sign-up is the step that switches roles on; MFA is a setting at the identity provider.
- No dedicated security officer, and the written policies have not been exercised. One operator answers. There is no on-call rotation. Two of the policies predate workspace isolation and are being brought up to date; the first access review has not been run.
- No managed key service and no key-rotation procedure. The application encryption key lives in the deployment environment on the host, and no confirmed copy of that environment exists off the machine.
- The audit trail is bounded by row count, not time (newest 2,000 per workspace), and is not shipped off-box. Keep your own copies if you need a longer archive. Request logs have no retention limit yet, and the web server's access log records query strings, which for an unsubscribe link or a sign-in redirect carry a signed token.
- Rate limiters are per-process — fine for one container, a real gap at scale-out.
- No proven backup yet. The job that copies the database off the server is installed on the production machine and the storage bucket exists, but we have not confirmed that a copy has landed on schedule, and no restore has been timed on the production machine. Until both are true this page does not claim backups.
- Monitoring alerts one person, by email. The external checks reach the operator's inbox; there is no paging and no error alerting beyond them, and nothing warns before a TLS certificate expires — certificates renew automatically, and nothing watches that they did.
- No uptime SLA, and no public status page.
- Deleting one individual's data is a manual process, and the erasure of a closed workspace after its 30 days is run by a person rather than a scheduled job.
- Org-held custody of backups and deliverables has not been proven against a live Salesforce org — it is covered by in-memory fakes. Choose it knowing that.
Reporting something
If you believe you have found a vulnerability, please tell us — we would much rather hear it from you. security@assemblywright.ai; details at /.well-known/security.txt. Privacy questions and rights requests: legal@assemblywright.ai.
Questions a review needs answered that are not here? Ask — we will answer directly, and add the answer to this page.