HIPAA audit trail, 45 CFR § 164.312(b)
HIPAA's Security Rule requires covered entities and business associates to implement audit controls that record and examine activity in information systems containing or using electronic protected health information (ePHI). That duty, and the assessment of whether it is met, stays with your organization. Verdifax records can serve as integrity evidence for the AI portion of your audit trail.
Status
Verdifax does not make any organization HIPAA compliant, and HHS does not certify products or vendors as compliant. Verdifax does not currently sign Business Associate Agreements, so do not send protected health information to Verdifax-hosted services. The mapping below is relevant to 45 CFR § 164.312(b) audit controls and is for your own assessment.
What § 164.312(b) actually says
"Implement hardware, software, and/or procedural mechanisms that record and examine activity in information systems that contain or use electronic protected health information."
That sentence is intentionally technology-neutral. It doesn't specify a format, a retention period, or a verification model. Whether an organization's audit controls are sufficient is for that organization, its risk analysis, and its auditors and regulators to decide.
Where audit trails fail in AI systems
A typical AI clinical-decision-support system produces a recommendation, the recommendation is logged with a timestamp + user id + model version, and that's the audit record. Two problems:
- The log is editable by anyone with database access. The integrity of the audit record depends entirely on the operator's promise to not modify it.
- The log doesn't reproduce the decision. If a clinician disputes the recommendation, "the model said X" is the entire audit trail, there's no way to reconstruct exactly what the model saw and how the recommendation was generated.
Both problems are exactly what Verdifax is designed to address.
Mapping
| HIPAA audit-control element | Verdifax contribution |
|---|---|
| Records activity in systems using ePHI | Every AI inference you send to Verdifax produces a sealed manifest hash; send identifiers and hashes, not PHI |
| Tamper-evident (anchored content) | On records sealed from run 239 on, changing any section of the record no longer matches the complete-record entry on the public log. Run 238 also carries that entry, but deleting it only lowers the verdict to partial coverage. On leaf v5 records sealed before run 238, changing any of the run's anchored values, which include the payload hash, the attested decision and the actor, no longer matches the public-log entry, while descriptive sections such as the request substance and approval chain are sealed only by hashes inside the bundle, so they show internal consistency, not that a party able to rewrite the whole bundle has not changed them |
| Reviewable | The PDF audit report at /runs/{id}/report.pdf is suitable for inclusion in incident response |
| Reconstructable | Given the run's sealed audit bundle, every section hash recomputes byte-for-byte from its recorded fields and every section is bound to the same manifest hash. In the pattern below the recommendation hash travels inside the payload, and on leaf v5 and later records the payload hash is one of the values bound to the public-log entry, so a later change to it no longer matches that entry. Since verifier 0.12.0, a public-log entry counts only if it is signed with a published Verdifax log-signing key and the timestamp the log signs for it verifies, so a rewritten record that anyone else logs as a new entry fails. Verdifax holds that key. From run 240 on, each record seals a 600-second anchoring window, so a later re-log, even by Verdifax, fails or must carry a new sealed date; earlier records show their authenticated anchoring time but cannot fail on it. |
Practical pattern
For a clinical decision support model:
import verdifax
# 1. Send hashes, never raw PHI or model output that may contain PHI.
import hashlib
phi_hash = hashlib.sha256(patient_record_canonical.encode()).hexdigest()
output_hash = hashlib.sha256(model_output.encode()).hexdigest()
receipt = verdifax.attest(
payload=f"phi_hash:{phi_hash}\nrecommendation_hash:{output_hash}",
program_id="<your-clinical-program-id>",
route_id="cdss-recommendation-v3",
registry_record_hash="<your-registry-record-hash>",
)
# 2. Store ALONGSIDE the recommendation in your existing audit log.
audit_db.insert({
"patient_id": patient.id, # internal id, stays in your own system
"user_id": clinician.id,
"recommendation": model_output,
"verdifax_seal": receipt.manifest_hash,
"timestamp": utcnow(),
})
The seal goes in your existing audit table. When the incident-response team needs to verify a specific recommendation later, they check the stored seal against the run's sealed record: GET /runs/{id}/verify re-derives the manifest hash server-side from the stored manifest fields, and the open-source verifier recomputes the audit bundle's section hashes offline and confirms each is bound to that manifest hash. Re-submitting the same inputs would create a new run with a different hash, so the check works from the sealed record, not from the inputs.
Why hash the PHI rather than seal the raw bytes
HIPAA's minimum necessary standard (45 CFR § 164.502(b)) limits uses and disclosures of PHI to the minimum necessary for the purpose. The Verdifax seal needs the identity of the input, not its contents. SHA-256 of the canonical PHI representation gives you input-identity without placing the PHI itself in the seal record. A hash of a short or guessable value can be confirmed by guessing, so a hash is not automatically de-identified. [Pending review by counsel: whether hashes or metadata derived from PHI are themselves PHI in a given deployment.] Keep the model output in your own audit log, as the example does, and send Verdifax only hashes and internal identifiers.
