Controls, evidence, and the gaps — verified 11 August 2026

Security

This page is written from an internal control audit dated 11 August 2026 in which every statement below was verified against a live system response, a configuration query, or a line of code — not from a marketing brief. Where a control is missing or not yet operating, it is listed in What we do not claim rather than omitted.

Encrypted in transit and at rest (AES). Never used for training. Never sold.
Encryption
PHI field encryptionProtected-health-information fields are individually encrypted with AES at the application layer before they reach the database, in addition to full-disk encryption of the database itself.
Key custodyThe encryption key is held in AWS Secrets Manager and injected into the running task at start-up. It is not in source control, not in a container image, and not in an environment variable in any build artifact.
Database encryptionAmazon RDS storage encryption with a customer-managed KMS key, automatic annual key rotation enabled. Automated backups and snapshots inherit the same key.
TransportTLS 1.2 and 1.3 only — TLS 1.0 and 1.1 are refused at the load balancer (ELBSecurityPolicy-TLS13-1-2-2021-06, live-tested). Plain HTTP is redirected to HTTPS. HSTS is sent with a one-year max-age including subdomains.
Database connectionsConnections to the database require TLS (rds.force_ssl = 1).
Object storageBoth S3 buckets: KMS default encryption, versioning on, all four public-access blocks on.
Tenant isolation
Enforced by the database, not by queriesTenant isolation is enforced by PostgreSQL Row-Level Security — a policy on the table itself, not a WHERE clause an engineer can forget.
The application role cannot bypass itThe serving database role is NOSUPERUSER and NOBYPASSRLS, and policies are declared FORCE ROW LEVEL SECURITY so they bind even the table owner.
Coverage113 of the 114 tenant-scoped tables carry an active, forced row-security policy. The one exception is listed under “What we do not claim” below.
Context cannot leak between requestsTenant context is set as a transaction-local session variable and re-applied on every transaction begin, so a pooled connection cannot carry one tenant's context into another tenant's request.
Proven, not assertedDuring the disaster-recovery drill on 2026-07-07, the application role without tenant context returned 0 rows from users, notes and episodes on a restored production snapshot.
Audit and logging
Append-only audit trailEvery access and privileged action is written to an audit trail that is append-only, enforced by database triggers. The application role cannot modify or delete audit history.
No PHI in the audit trailAudit records carry identifiers, action verbs and timestamps only — no clinical content — so they can be retained long term and exported to a customer SIEM.
Impersonation is stampedSupport “view as” sessions are read-only and every resulting audit row records the operator who initiated them.
Infrastructure auditAWS CloudTrail is enabled across all regions with log-file validation and KMS encryption. Log groups retain 400 days. Alarms fire on root-account use, trail configuration change and administrative user creation.
Infrastructure and access
Network positionApplication servers run in private subnets with no public IP address. The database is not publicly accessible and accepts connections only from the application security group.
IdentityThere are no long-lived IAM users in the production account. All human access is a short-lived assumed-role session.
SecretsAll ten runtime secrets are held in AWS Secrets Manager and injected at start-up. No secret value is stored in an environment variable, a container image, or source control.
Least privilegeThe task role's model-inference permissions are scoped to named model families; its Cognito permission is scoped to one user-pool ARN and its email permission to one identity. The execution role can read exactly nine named secret ARNs.
ContainersThe application container runs as a non-root user (uid 10001).
AvailabilityDatabase is Multi-AZ with deletion protection. Two application tasks run behind the load balancer with CPU target-tracking autoscaling.
Application security
SQL injectionAll database access is parameterized. A repository-wide scan of all 211 raw-SQL call sites found zero dynamically constructed statements.
Code executionThe application contains no eval, exec, or shell-execution paths.
Static analysisbandit runs on every change and gates at zero medium-or-higher findings.
Dependency, image and SBOM scanningpip-audit, trivy and a CycloneDX SBOM run on every change to main and weekly on a schedule. Accepted advisories are documented individually with a reachability analysis and a named permanent fix.
Rate limitingPer-IP rate limiting at the edge and in the application, with tighter limits on login, signup, token and password-reset endpoints. Request bodies are size-capped, including chunked uploads.
Response headersX-Frame-Options: DENY, X-Content-Type-Options: nosniff, a restrictive Permissions-Policy (microphone on our own origin only; camera, geolocation, payment and USB denied), Referrer-Policy, and Cross-Origin-Opener-Policy.
Cross-site request forgeryNot applicable by design: the API authenticates with an Authorization: Bearer header, never an ambient cookie, so there is no cross-site request to forge.
Vulnerability disclosurePublished at /.well-known/security.txt (RFC 9116). Reports go to security@tebscribe.com.
Vendors and AI
Where inference runsAll large-language-model inference runs on Amazon Bedrock inside our own AWS account, under our signed AWS Business Associate Agreement.
Business Associate AgreementsSigned with AWS and with Deepgram, our speech-to-text provider (countersigned 2026-08-02).
No training on your dataSpeech-to-text requests are sent with the vendor's model-improvement program explicitly opted out, on both the batch and the realtime path, guarded by an automated regression test that fails the build if the flag is dropped.
On-device optionFree-tier dictation runs on the device; that audio never leaves the phone.
Subprocessor registerWe maintain a register naming every third party that processes customer data, what it processes and its BAA status. Available on request with a security questionnaire.
Backup and recovery
BackupsAutomated database backups retained 35 days, with point-in-time recovery available. Backups inherit the database's customer-managed KMS key.
Restore has actually been testedOn 2026-07-07 we restored a production snapshot to a throwaway instance and measured a recovery time of 2 minutes 39 seconds against a four-hour objective; integrity was confirmed on record counts only. The procedure is written up as a repeatable runbook. This is one dated drill, not a demonstrated cadence.

What we do not claim

A security review is faster when the gaps are on the first page. These are ours, as of 11 August 2026.

Security questionnaires and reviews

Send questionnaires, BAA requests, architecture-review requests, and vendor-risk paperwork to security@tebscribe.com. We answer from the audit evidence behind this page and we will tell you when the honest answer is “not yet”.

Vulnerability reports: /.well-known/security.txt (RFC 9116) or the same address.

Controls verified 11 August 2026. This page is re-verified before it is changed.

Charts done before you leave the building.

tebIQ is physician-built AI documentation. Try it free — no demo call, no sales rep.

Start free