Security & data handling · Reviewed 2026-08-31
Twelve answers in the order a diligence checklist asks them — isolation, authentication, authorization, audit, encryption, transport, secrets, logging, PHI, subprocessors, incident response, BAA — each carrying the implementation it comes from, and each marked supported, in progress, product capability, or not held.
How to read this page
Three claims that previously stood here did not survive being measured against the code — a purge that does not happen, an HSTS header that is not set, and a breach-notification figure the published agreement does not state. They were corrected rather than left standing. Where a control has a limit, the limit is in the same paragraph as the control.
The checklist
Tenant context is server-authoritative. In production this application sends no tenant identifier at all: the request-header builder reads tenant and user only from server-validated auth claims, and it emits tenant headers only when the API host is localhost, for local development. In every deployed environment the backend derives the tenant from the bearer token, so there is no client-supplied value to tamper with.
An earlier implementation read a tenant id from browser local storage as a fallback. It was removed as client-controlled and untrustworthy for PHI, and the header builder now raises an unauthenticated error rather than continuing without server-issued claims.
Ask us to walk through: src/lib/epcr-clinical.ts (buildEpcrHeaders), src/lib/auth-store.ts, src/hooks/useIncidents.ts
Sessions are carried in HttpOnly cookies. The refresh endpoint accepts a refresh token only from the HttpOnly cookie — the request-body fallback was removed, and its absence returns 401 rather than degrading to a weaker path. The rotated refresh token is deliberately not returned in the response body, so script running on the page cannot read it. Session cookies are Secure in production and SameSite=Lax.
Authorization claims are the identity service's answer to a server-side validation call, not a decoded copy of the token the browser happens to hold, and they are kept in memory rather than in local storage. Privileged surfaces additionally require a step-up multi-factor check whose freshness window is matched to the backend.
Ask us to walk through: app/api/auth/refresh/route.ts, src/middleware.ts (validateWithCore, MFA freshness), src/providers/AuthProvider.tsx, src/lib/auth-store.ts
Access is evaluated by tenant, role, module entitlement and explicit permission. A tenant mismatch is a hard failure before any other check is considered, and elevated founder authority explicitly does not extend into patient or investor scopes. Edge middleware gates routes by audience before a page renders; component guards gate individual controls inside a page.
Said precisely, because the distinction matters to a reviewer: those are the edge and client gates, and they live in this codebase. The authoritative enforcement is in the API services, which are separate systems and are not shown by this page. We will not present a frontend gate as if it were the server's decision.
Ask us to walk through: src/lib/policies/index.ts (can), src/components/guards/PermissionGate.tsx, src/middleware.ts (audience + founder-prefix gates)
Audit records are append-only and hash-chained: each record references the hash of the record before it, so a removed or altered entry breaks the chain and is detectable rather than silent. Narcotics chain-of-custody and signature records expose the prior hash directly in the operator view.
There is a verification surface that needs no login at all: a signed document's public verification page marks it authentic only when both the content hash matches and the chain integrity check passes, and says “hash chain broken” when it does not. Stated exactly: the chains are written by the platform services; this application surfaces and verifies them.
Ask us to walk through: app/verifications/signature/[verificationId]/page.tsx, app/workspace/narcotics/chain-of-custody/page.tsx, app/workspace/trustsign/verify/page.tsx
PHI is encrypted before it is written to browser storage: AES-GCM with a 256-bit key that is generated non-extractable, so its bytes never exist in JavaScript, with a fresh random initialisation vector per record. Each record is scoped to user, tenant and schema version, and records older than seven days — longer than any realistic offline shift — are refused on read.
Signing out purges the key, which leaves any residual ciphertext undecryptable. Switching tenant does not purge, deliberately: the offline outbox can hold unsynced field work, and destroying it would lose a chart. Instead, records carrying a different scope are refused on read.
The boundary, stated rather than glossed: only the PHI payload is encrypted. The routing envelope a sync queue needs to function — idempotency key, chart id, workflow state, sequence, timestamps — stays in plaintext so browser indexes work, and the chart id is an opaque identifier. This defeats disk inspection, profile and backup exfiltration, and casual developer-tools reading. It does not defeat script running on the same origin, which can ask the same key to decrypt. The identity binding and the sign-out purge are what stop the next user of a shared tablet from reading the previous user's chart.
Ask us to walk through: src/lib/epcr-offline-crypto.ts, src/lib/continuity-secure-store.ts, src/providers/AuthProvider.tsx (sign-out purge), tests: src/__tests__/epcrOfflinePhiEncryption.test.ts, src/providers/__tests__/signout-phi-purge.test.tsx
Every response carries a Content-Security-Policy generated per request with a fresh nonce: scripts must carry that nonce, inline script is not allowed through a blanket exemption, framing is denied outright, plugin objects are denied, and base URI and form targets are restricted to this origin. Connection, image and media sources are explicit allowlists rather than wildcards.
Alongside it: content-type sniffing off, framing denied, a strict cross-origin referrer policy, and a permissions policy that denies camera, geolocation, payment, USB and cohort tracking outright.
Not claimed here: HSTS. No Strict-Transport-Security header is set anywhere in this application. If one is set it is edge configuration this page cannot show you, so it is not asserted.
Ask us to walk through: src/middleware.ts (nonce CSP), next.config.mjs (response headers)
Committed-secret scanning runs as a repository pre-push gate: a gitleaks scan runs against staged changes with a documented, reasoned allowlist, and the gate fails rather than passing quietly if the policy file is present but the scanner is not installed. Third-party integrations are called server-to-server; no third-party provider secret is ever issued to a browser.
Not claimed here: that continuous integration blocks committed secrets. The pull-request workflow runs toolchain policy, type checking, linting, static scanners, sharded tests and a build — it does not run a secret scan. The pre-push hook is the gate that exists, and naming it precisely is more useful to you than a broader claim.
Ask us to walk through: .gitleaks.toml, .githooks/pre-push, scripts/local-ci.sh, .github/workflows/pr-validation.yml
Diagnostic logging on protected paths records the route, the decision reason and the status code, and is written not to carry PHI, secrets or full URLs containing credentials. In customer-facing list views, patient names, dates of birth and identifiers are masked at the presentation layer, and a patient name is never placed into a URL or query string.
Not claimed here: an automatic PHI-redaction layer inside the logger. What exists is display masking plus logging paths written not to carry PHI. There is no scrubbing wrapper, so this page does not describe one.
Ask us to walk through: src/lib/phi-mask.ts, src/middleware.ts (audit-event emission)
PHI reaches this application only for an authenticated, authorized user acting inside their own tenant, and it is handled as a business associate under each agency's executed Business Associate Agreement. On the device it is encrypted as described above; in list views it is masked; in URLs it does not appear.
The automation surface is documented rather than implied: every agent tool that touches PHI is labelled PHI-bearing in the published tool reference, writes are approval-gated, and policy resolution fails closed. That reference is public — read it on the developer page rather than taking this paragraph's word for it.
Ask us to walk through: app/developers/page.tsx (tool reference), /legal/baa, src/lib/phi-mask.ts
The subprocessor set is published, not summarised: cloud infrastructure, the outbound claims clearinghouse, payment processing, transactional email, billing telephony, self-hosted realtime audio for crew operations, physical mail for statements, and identity. Each is bound by contract and, where PHI is involved, by a written BAA. The authoritative list — and the process for requesting the current one — is section 4 of the privacy notice, so there is one list rather than a marketing copy of it here.
One boundary worth naming for billing diligence: a clearinghouse an agency used before AdaptixCore stays in scope only as a historical-data migration source. No claim is submitted outbound through it.
Ask us to walk through: app/privacy/page.tsx (section 4, service providers and subprocessors)
Suspected security issues go to security@adaptixcore.com and are acknowledged within one business day. A confirmed incident affecting an agency's data triggers the breach-notification obligations in that agency's executed BAA, using the contact and timeline that agreement specifies.
Not claimed here: a 24/7 security operations centre. There is not one. Response is founder-and-engineering escalated against the commitment above, and current service state is visible on the live status page.
Ask us to walk through: app/security/page.tsx (this commitment), /legal/baa, /status
AdaptixCore operates as a business associate. The agreement's clause structure — permitted uses and disclosures, safeguards, sub-contractor obligations, breach notification, term and termination, and the destination of PHI when the agreement ends — is published at /legal/baa, and the current template is requested from the address on that page. It is executed at onboarding alongside the Master Services Agreement.
HIPAA has no federal certification programme, which is why every surface here writes “HIPAA-aligned, under BAA” and never “HIPAA certified”.
Ask us to walk through: app/legal/baa/page.tsx, app/legal/msa/page.tsx
Certification & compliance state
These entries are rendered from the platform's claims evidence registry, not written as copy beside it. When a claim's evidence changes, the registry entry changes and this list follows; a claim without current evidence disappears instead of quietly ageing into something untrue.
v3.5.1 Collect Data
Issued by the NEMSIS Technical Assistance Center for the 'Collect Data' exchange category against NEMSIS schema v3.5.1. This is a data-exchange compliance badge for that category and schema version, not a blanket certification of the platform.
Evidence confirmed 2026-08-13 · re-verify by 2027-08-13
Aligned
Operating posture only. HIPAA has no federal certification program, so "HIPAA-aligned" (not "HIPAA certified" or "HIPAA compliant") is the accurate framing per the project's own public-copy rule.
Evidence confirmed 2026-08-04 · re-verify by 2027-02-04
In progress
Audit engagement described as in progress. No completion evidence or completion date is confirmed anywhere in this repository as of the audit date below.
Evidence confirmed 2026-08-04 · re-verify by 2026-11-04
Not held, and no HITRUST engagement has begun. Listed so its absence is an answer rather than a gap you have to notice.
None has been performed. When one is engaged, its scope, date and remediation status will be summarised here.
Not in place. Incident response is founder-and-engineering escalated against the commitments on this page.
Not held. The Type II engagement is in progress and is shown above with its real state; no Type I report exists to present.
Security questions?
Use the contact form for a vendor security questionnaire, a diligence request, or a BAA conversation. For a suspected vulnerability, write directly to security@adaptixcore.com — acknowledged within one business day.