Skip to content
BitExactdocs
Documentation
On this page

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 Authorization headers are forwarded upstream and never recorded. An identity's on_behalf_of names the party a run acted for, and the run index (a cache of the runs, rebuilt by bitexact 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 under BITEXACT_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 what bitexact repair merges, so the proxy's BITEXACT_DATA_DIR must 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.
  • Who can read the files.

    • Every directory BitExact creates under BITEXACT_DATA_DIR is 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 health warns (store-permissions) if other accounts on the host can enter BITEXACT_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 init makes 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.
  • 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 says view 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 and data/runs/*.bundle.json ever disagree, the bundles are the record. An organization that forbids opening HTML uses the bundles and workpaper.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 runs and names every payload file the verdict does not stand behind - data/workpaper.md, data/trust.json, data/verification/verify-procedure.md among 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-sealed exists 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_ALG selects 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 keygen makes 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), or Ed25519 only - not resistant to a quantum forger) and whether the ML-DSA key was pinned. A verifier whose cryptography has 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-receipts says 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.
  • 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 health names 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 health prints signing: hybrid ML-DSA-65, or warns signing_classical_only for 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 its SHA256SUMS with 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, uvicorn and our own bitexact-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 areaEvidence artifact
Change managementSigned release pipeline, hash-pinned lockfile, SBOM per release
Cryptographic controlsHybrid Ed25519 + ML-DSA-65 signing (see "Post-quantum coverage"), key-rotation runbook, FIPS-selectable SHA-256 mode
Access / least privilegeDeny-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 & disposalbitexact purge/archival tooling, write-ahead redaction with audit trail
Integrity monitoringFail-loud replay divergence, verifier exit codes, external anchoring
Vendor / subprocessor riskSelf-hosted, no subprocessors touch customer data

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.