Security & compliance
What we actually implemented, named so you can check it
Security pages are usually a list of adjectives. This one lists controls and the file each is implemented in, because a claim a reviewer cannot verify is not worth making. It describes how things are built today. It is not a warranty, and no system is perfectly secure.
Our certification status, stated plainly
We are not SOC 2 certified, and we will not imply otherwise on a marketing page. We are a small firm that has not been through that audit. What we offer instead is specificity: the controls below are real and named so you can check them, we will answer your security questions in writing before you buy, and a requirement your organisation has — data kept in Canada, recordings disabled, a shorter retention period — can be written into the agreement rather than promised verbally. If a current SOC 2 report is a hard procurement requirement, tell us early and we will say so rather than waste your review cycle.
This website
Controls implemented in the site you are reading
If we cannot secure our own marketing site properly, there is no reason to believe we will secure the system that answers your phone.
Transport security
- Every response is served over TLS. Plain HTTP requests are answered with a 308 redirect to the HTTPS origin before any application code runs (src/proxy.ts).
- HSTS is sent on every response with a two-year max-age, includeSubDomains and preload, so a browser that has seen this site once will refuse to downgrade.
- The policy header is set in two places deliberately — next.config.ts covers static responses, the proxy covers redirects and 404s.
- upgrade-insecure-requests is set in production, so any legacy sub-resource reference is rewritten rather than silently blocked.
Content Security Policy
- A fresh nonce is generated per response and script-src carries 'strict-dynamic'. There is no 'unsafe-inline' in script-src anywhere, including for the theme script and the structured-data block.
- frame-ancestors 'none' and X-Frame-Options: DENY — this site refuses to be framed, which is the standard defence against clickjacking.
- connect-src 'self' is there to stop a script that did somehow execute from sending form data to another origin.
- frame-src allows exactly one outside origin, calendly.com, for the booking calendar on the contact page. The frame is not requested until a visitor opens it, and it is a plain iframe — no Calendly script runs in our page (src/components/booking-embed.tsx).
- Fonts are self-hosted at build time, so font-src 'self' is honest and no visitor's browser contacts a third-party CDN.
- style-src keeps 'unsafe-inline' because React and the animation library write transforms to style attributes; the residual risk is CSS injection, not script execution, and we state it rather than hide it.
Input validation and output encoding
- Every submitted field is normalised (control characters, zero-width and bidi-override characters stripped), length-capped and pattern-checked before anything else happens (src/lib/validation.ts).
- The client and the server run the same validator, and the server's verdict is the only one that counts — the client copy exists to give fast feedback, not to be trusted.
- Encoding is context-aware: HTML text, HTML attribute, log line and spreadsheet cell each have their own encoder. CSV exports neutralise leading =, +, - and @ so a lead cannot become a formula in Excel.
- Requests are rejected on content type, origin (Fetch metadata first, Origin header as fallback), declared size and actual byte length, in that order, before the body is parsed.
- Submissions are rate limited per client, and two bot heuristics — an off-screen honeypot and a minimum fill time — are applied before a record is created.
Access control and least privilege
- There is no database behind this site and the browser has no data-store credentials of any kind. The only write path from a visitor is POST /api/contact, which accepts one validated shape.
- Administrative paths (/admin, /api/internal) return 404 on the public origin. They are served only when the request arrives on a separate, access-controlled host named in ADMIN_HOST.
- Roles are enumerated in code with explicit permission lists — viewer reads, operator exports, admin deletes (src/lib/rbac.ts). Adding a capability shows up in a diff.
- Credentials are compared in constant time, rejected below 24 characters, and resolved server-side only. No role, token or permission list is ever sent to the browser.
- With ADMIN_TOKENS unset there are no principals at all, so the internal surface fails closed by default rather than open.
- Every administrative access is written to a structured audit line with the actor label and the permission exercised — never the credential.
Your deployment
Controls that travel with the systems we build
This is how we normally build, within what the third-party platforms involved allow. The specifics for your system are the ones written into your agreement.
In the systems we deploy for you
- Least-privilege service credentials, scoped per integration. A booking agent that needs calendar write access does not get contact delete.
- Human approval gates designed in for anything financial, legal or clinical — the agent prepares, a person commits.
- A structured audit log of the actions an agent takes, with the inputs it acted on.
- Storage region (Canada or the United States), retention period and whether recordings are kept are agreed with you and set in your agreement.
- We do not use your conversations to train models of our own, and we choose model-provider tiers whose terms say submitted content is not used for training.
- Prompts, sequences, transcripts and the knowledge base are yours. Export and deletion are set out in your agreement.
- Most systems run on third-party platforms — voice, telephony, AI models, automation tools. Their security, uptime and data handling are governed by their own terms, which we do not control.
Security questions
What procurement teams ask us
Reporting a vulnerability
Email info@firstpilotinc.ca with "Security report" in the subject. We aim to acknowledge within one business day, and we will not pursue anyone who reports a genuine finding in good faith. Please do not run automated scans against this site without asking first.
Where is call and chat data stored?
In the region agreed with you — Canada or the United States — for the retention period set in your agreement. Recordings can be switched off if transcripts are enough for you. If keeping data in Canada matters to you, raise it during scoping.
Are you SOC 2 certified?
No, and we will not imply otherwise. We are a small firm and we have not been through a SOC 2 audit. What we can do is show you exactly how a deployment is secured, answer your security questions in writing, and write any specific requirement you have into the agreement. If a current SOC 2 report is a hard procurement requirement, tell us early and we will say so rather than waste your review cycle.
How do you handle PHI or other regulated data?
For clinics we scope the agent to book, reschedule and route rather than collect clinical detail, and anything diagnostic is routed to staff. Where regulated health information cannot be avoided, how it is handled is agreed in writing before anything is built.
Data handling is set out in full in the privacy policy, and what this website is and is not in the terms of use. Commitments specific to your deployment go in your written agreement.
No obligation · no sales sequence
Send us your security questions
We would rather answer them before you buy than during an incident. Send your questionnaire with an enquiry, or just ask what you want to know — we will answer in writing, and we will tell you plainly where the answer is 'we don't do that'.