BitExact compliance pack#
Standing answers for the security and procurement reviews an enterprise buyer runs before a self-hosted deployment. Nothing here claims BitExact makes a buyer compliant with any regime; it documents the properties a reviewer can verify, and points to the evidence.
Deployment and data handling#
- Customer-VPC only. BitExact runs entirely inside the customer's infrastructure. There is no BitExact-hosted service, no multi-tenant plane, and no telemetry. This is architectural, not a policy toggle: nothing in the codebase phones home.
- Customer data never leaves customer infrastructure. Recorded model calls, tool calls, and payloads are written to storage the customer controls. Two things leave, both opt-in and neither carrying recorded content: external anchoring sends only a SHA-256 hash of a run's head to a customer-configured RFC 3161 timestamp authority, and configured event delivery sends signed notifications - metadata such as a run id, a step count, a head hash or an alert's kind - to customer-configured destinations (a webhook, Splunk or Datadog). No recorded payload is in either. An event is a signed notification, not evidence: it is in no bundle or pack and the verifier never reads it, so a receiver that needs a verdict verifies the run the event names.
- Licensing is offline, and required. A signed license key file is validated locally against a vendor public key that every delivered wheel and image has built in at release, so the licensing trust root is not configuration the customer sets. No license check contacts any network service, so an air-gapped deployment is fully functional. BitExact is licensed use only: without a valid license nothing records or replays, and agents' calls pass through the proxy unrecorded (refused only under strict mode); an expired license, once its grace period (14 days unless the license names another) is over, leaves the deployment read-only (recorded evidence stays listable, verifiable and exportable; nothing new is produced) and does not lapse into a working mode. A license binds to the deployment's recorder key — one deployment per key — and a license that names none records nothing. It is renewed every 90 days by file, with a TPM attestation of the recorder host; a missed renewal keeps recording and every sealed run says so. The standalone Apache-2.0 verifier is the deliberate exception and needs no license, so your evidence stays checkable by any third party regardless of your license state.
Data at rest#
What is stored, where, and who protects what.
What the evidence holds. Each run's model requests and responses, tool arguments and results, and the identity and decision records the integration supplies. That routinely includes personal data. API keys and
Authorizationheaders are forwarded upstream and never recorded. An identity'son_behalf_ofnames the party a run acted for, and the run index (a cache of the runs, rebuilt bybitexact reindex) holds the party each run's identity names now, so a search can propose the runs acting for a party; each is confirmed against the run's own chain, and an evidence pack selected by party reads every chain in its window. A redacted party leaves the index with it. The workpaper shows the identity a run opened with beside the one it ended with, and every change between, at the step it happened. Record a pseudonymous id there (user:7f3a9c), never a name or an email, and resolve it to a person in your own systems (identity-access.md, "Who a run acted as, and for whom").Where it is. It depends on the backend.
- File backend: everything is under
BITEXACT_DATA_DIR- runs and their sidecars, governance and case ledgers, the refusal ledgers of runs refused at open, documents, the transparency log, the access log, the archive catalog and the run index. - PostgreSQL backend (
BITEXACT_DATABASE_URL): all of that is in the database, and so are pending redaction requests and every run's regress and fork-matrix reports. One kind of file is still written underBITEXACT_DATA_DIR/runs/: the recording proxy's stream journals. A stream journal is the proxy's write-ahead copy of a streamed response while it is being relayed; the proxy merges it into the chain when the stream ends and deletes it. If the proxy dies mid-stream the journal is whatbitexact repairmerges, so the proxy'sBITEXACT_DATA_DIRmust be persistent storage on the proxy's host - the Compose deployment's named volume is. The recorder service, which the Kubernetes template runs, writes events straight to the database and keeps no journals; the viewer writes none. - Beyond the store, BitExact writes evidence only where an operator
points it: an archive (
bitexact archive,bitexact purge --archive), and the exports, evidence packs and bundles a person asks for. No copy leaves the deployment unless a person exports it.
- File backend: everything is under
Who can read the files.
- Every directory BitExact creates under
BITEXACT_DATA_DIRis owner-only (0700), under either backend, and every file the store writes there is owner-only (0600). A directory that already exists keeps the mode its operator gave it. - In the image the store is
/data, owned by the image's user (uid 10001) and owner-only. bitexact healthwarns (store-permissions) if other accounts on the host can enterBITEXACT_DATA_DIR, whichever backend is configured.- An archive directory BitExact creates is owner-only (0700), and the bundles, sidecars and reports it writes there are owner-only (0600). Point the archive at storage only BitExact's account can read.
- Files BitExact keeps for itself outside the store are owner-only too:
the collector's spool (0700, with its keys and secrets 0600), a
witness's state directory, and the directory
bitexact pki initmakes for the CA key. Certificates and revocation lists are public. - Exports, evidence packs and bundles are written where the person
running the command names, with that process's umask: they are made
to be handed to someone. Write them into a directory only you can
read, or run the command with
umask 077. - With PostgreSQL, access to the rows is the database's: give the BitExact role its own database and grant no other role access to it.
- Every directory BitExact creates under
Encryption at rest is the platform's. BitExact does not encrypt the store. Its controls are integrity controls: the hash chain, the recorder's signatures, external anchors and the transparency log make any change detectable. They do not make the bytes unreadable. Encrypt where the evidence lives:
- an encrypted volume (LUKS/dm-crypt, or your cloud's disk encryption with a customer-managed key);
- an encrypted managed database (storage encryption or TDE);
- and the backups of either.
Encryption at that layer is invisible to BitExact, and verification is unaffected by it.
The collector's spool. Events waiting on an agent host before they reach the recorder are encrypted (ChaCha20-Poly1305). Each segment key is wrapped by a host key that never leaves the collector's spool directory. Only the recorder's store holds plaintext.
Keys. The recorder's signing key can live in an HSM (PKCS#11) or be held under a KMS envelope instead of a file (Recorder-key custody).
Removing personal data.
- Redaction destroys a field's value and salt in place, under two-person control, and keeps its commitment, so the run still verifies.
- Retention purges whole runs past their deadline, unless they are under legal hold. Each purge leaves a record signed with the recorder key - what went, when, and by which command - so the transparency log reads the run as purged, not lost (Transparency log).
- Archiving moves old months out of the live store, each run as a verifiable bundle.
- A redaction is itself an entry on the run's chain, naming who requested and who approved it.
Evidence integrity#
- Every run is a hash-chained manifest with per-field salted commitments;
the open-source verifier re-derives every hash and signature from first
principles (
docs/auditor-verification.md,docs/bundle-spec.md). - Redaction removes a value and its salt write-ahead, leaving a signed audit entry and a standing commitment — GDPR/CCPA erasure where the data lives, without breaking verification.
- External anchors (RFC 3161 timestamps, WORM/object-lock export) pin a run's head outside the customer's mutable store, so rollback by a party with write access is detectable.
- An execution BitExact refused to record - a lapsed license, a missing or
unlicensed recorder key, a faulty signer or store - still runs, and its
refusal is a hash-chained event, signed with the recorder key when one
loads and entered in the transparency log. Capture coverage counts it as
an execution without evidence, workflow and selection evidence packs
carry it, and the open-source verifier checks it
(
docs/capture-coverage.md). A single-run or case pack says in its workpaper which refusals it covers. - The reading view. Every evidence pack and provenance bag carries
data/view.html: its runs as readable steps, in any browser, offline, and every workpaper - run, workflow, selection and case - says so in its independent-verification section when the pack carries the page. It is a reading aid and proves nothing. Its first line says it is not a verification result, and it shows no verdict. The verifier's own code renders it from the bundles when the pack is made, the bag's checksums seal it, and the verifier renders it again from the bundles and fails the pack (exit 2) if the page differs, so it cannot tell a story the bundles do not. When it matches, the OK line saysview matches the bundles. The page has no script, no external reference, no form and no link out of itself, under a Content-Security-Policy that refuses all of them; it reads the same with JavaScript off, and it is plain text that a text editor shows. If the page anddata/runs/*.bundle.jsonever disagree, the bundles are the record. An organization that forbids opening HTML uses the bundles andworkpaper.md, or asks for a pack made with--no-view, which verifies without the page. - What the verifier does not check. After its OK line on a pack, the
verifier prints
not checked against the runsand names every payload file the verdict does not stand behind -data/workpaper.md,data/trust.json,data/verification/verify-procedure.mdamong them: the producer's own statements, which the bag's checksums seal against later change and nothing more. - Scope. BitExact proves the captured trajectory is intact, honestly
redacted, and carries every value a replay would need. It proves the run
un-truncated only when the bundle is sealed - an unsealed bundle still
passes and makes no claim about the end of the run, which is what the
verifier's
--require-sealedexists to enforce. Re-execution itself is not proved by verification: the offline verifier runs no replay. It does not assert that the capture is the complete set of calls an agent made: a call made outside the model and tool interfaces BitExact records is not captured. This boundary is stated in the auditor procedure (docs/auditor-verification.md). - Regulatory mapping. Regulatory mapping and the published compliance mapping map BitExact's properties to the clauses of FINRA Rules 4511, 3110 and 2210 and SEC Rule 17a-4. None of these rows says a firm meets SEC or FINRA requirements; each row states evidence and its limit.
Post-quantum coverage#
Evidence is kept for years, and an Ed25519 public key sits in every checkpoint, so a quantum computer built later could recover the key and re-sign a doctored history. What BitExact signs, and what it does not:
- Hybrid signatures. Every object the recorder key signs - checkpoints,
WORM anchors, transparency-log notes, capability tokens, retention
records, ledgers and refusal records - and every bundle signature, DSSE
envelope and signed report made with a hybrid key, carries an ML-DSA-65
signature (FIPS 204; ML-DSA-87 where
BITEXACT_PQ_ALGselects it) beside its Ed25519 one. A license signed with the vendor's hybrid key carries both halves, and a release with the vendor's ML-DSA key built in checks both. Both halves sign the same bytes, and the ML-DSA half also binds the Ed25519 public key and the kind of object, so it cannot be moved onto another key or another kind of record (docs/bundle-spec.md, "Post-quantum signatures"). - Keys.
bitexact keygenmakes both halves and prints the trust-file entry that pins them together. The ML-DSA half lives where the Ed25519 key does: a file, a PKCS#11 3.2 token (CKM_ML_DSA), or a KMS envelope (recorder-key-custody.md). - The protection holds for a relying party who pins the ML-DSA key -
with a trust-file entry's
pq_public_key,--expect-recorder-pq-key, or--require-pq- because a forger who recovered the Ed25519 key can add an ML-DSA key of their own. Pinned, a stripped or substituted ML-DSA half fails verification. Unpinned, a run whose ML-DSA half drops out or changes key part way through still fails; a rotation to a new ML-DSA key passes only when the trust file lists the new key. - Every verdict says what it checked. The verifier's OK line names the
suite (
signatures: Ed25519 + ML-DSA-65 (post-quantum), orEd25519 only - not resistant to a quantum forger) and whether the ML-DSA key was pinned. A verifier whosecryptographyhas no ML-DSA says the half was not checked, and fails when a pin requires it. - What stays classical, and why.
- Attestation receipts are Ed25519 only: their external format defines no
post-quantum algorithm, and
verify-receiptssays so. The run's hybrid checkpoints are the time proof. - An RFC 3161 token is signed by the TSA's key, not ours. An ML-DSA TSA (RFC 9882) gives a post-quantum time anchor; a classical TSA's token is named "classical" in the verdict. It still binds the head; only its time claim is open to a quantum forger.
- The mTLS certificates between collectors and the recorder need no post-quantum signature. They authenticate a peer during a handshake, and no evidence rests on them afterwards: a certificate forged later opens no past session and changes no signed record.
- Attestation receipts are Ed25519 only: their external format defines no
post-quantum algorithm, and
- In transit. Collector traffic carries personal data, so it must not be
readable later either: the recorder never narrows the key-exchange groups
its OpenSSL offers, and on OpenSSL 3.5 that includes the X25519MLKEM768
hybrid.
bitexact healthnames the group the last collector handshake negotiated where the recorder's OpenSSL can name it (3.2 or later), and warns on a classical one. - Deployment signals.
bitexact healthprintssigning: hybrid ML-DSA-65, or warnssigning_classical_onlyfor a key without its ML-DSA half; the recorder logs the same warning when it starts. - External truth. The ML-DSA checks are held to the C2SP Wycheproof and NIST ACVP vectors (vendored, pinned to the upstream bytes), to Go's, Node's and the JDK's ML-DSA verifying the product's signatures, to Sigstore's ML-DSA timestamp authority, and to a PKCS#11 3.2 token.
Supply chain#
- Pinned runtime dependency closure (
requirements.lock), CycloneDX SBOM (scripts/gen_sbom.py), digest-pinned base image; the release pipeline signs each release image and itsSHA256SUMSwith cosign and the BitExact release key, whose public half customers pin, and attaches the SBOM to the image. - The dependency set is deliberately small and stdlib-first; each addition
is a reviewed line item. The current runtime deps are
cryptography,asn1crypto,starlette,httpx2,uvicornand our ownbitexact-verifier, resolving to a closure of 14 packages that is held as an allowlist: a package that enters it - including one an upstream release adds transitively - fails the test suite until it is admitted deliberately. - That closure is audited for known vulnerabilities on a schedule, not
only on our own changes, because a shipped pin becomes vulnerable with no
commit on our side. Criteria, the measured hygiene of each dependency, and
what the scan does not cover are in
supply-chain.md.
SOC 2 evidence kit (what we provide on request)#
This maps common SOC 2 Type II control areas to the artifact a reviewer can inspect. It is an index to evidence, not an assertion of certification.
| Control area | Evidence artifact |
|---|---|
| Change management | Signed release pipeline, hash-pinned lockfile, SBOM per release |
| Cryptographic controls | Hybrid Ed25519 + ML-DSA-65 signing (see "Post-quantum coverage"), key-rotation runbook, FIPS-selectable SHA-256 mode |
| Access / least privilege | Deny-by-default route authorization over three built-in roles plus custom roles the deployment defines; per-principal workflow and environment scope; authorization re-evaluated every request with no session and no cached decision; append-only access log; non-root container; per-run OS write lock. See identity-access.md. |
| Data retention & disposal | bitexact purge/archival tooling, write-ahead redaction with audit trail |
| Integrity monitoring | Fail-loud replay divergence, verifier exit codes, external anchoring |
| Vendor / subprocessor risk | Self-hosted, no subprocessors touch customer data |
Legal exhibits#
The DPA, security exhibit, SLA and source-escrow rider are negotiated per engagement and attached to the MSA as exhibits. Ask for the ones your review needs; do not assume this pack stands in for them. This pack is the technical evidence a reviewer verifies alongside them, and it is deliberately silent on the commercial terms.