Rule analysis · Governance Evidence Pack

Which HIPAA Security Rule requirements can your data platform's logs give evidence for?

DuckDB2026-10-18Script and CSV downloadable

The short answer

By our rating, your data platform's logs give evidence for 22 of the 63 HIPAA Security Rule items (34.9%). One needs only the log. Twenty-one need a second record, such as a policy, ticket or HR date. The other 41 are not recorded in platform logs. Grant history shows when access was given and removed.

What you will have at the end

A Python script, hipaa_log_evidence.py, that fetches the text of the HIPAA Security Rule, lists every standard and implementation specification in it, checks that list against the rule’s own matrix, rates each item for what a data platform’s logs can show, and counts. It writes the 63 rated items as hipaa_log_evidence.csv. The ratings are our judgment, written out in the script so you can change them.

This page rates a rule. It is not a finding that anyone complies. Whether a log is enough evidence for an item is for your compliance team and your auditor to decide.

The three ratings

  • Direct: a platform’s own log, by itself, shows that what the text asks for happened or is in place.
  • Partial: the log shows part of it. Another record (a policy, a request, an HR date, a sign-off) shows the rest.
  • None: what the text asks for is not something a data platform’s logs record, such as a contract, a training record or a locked door.

“Standard” and “implementation specification” are the rule’s own terms. Each standard states a requirement. Some standards have implementation specifications, each marked Required or Addressable. For an addressable specification, 45 CFR 164.306(d)(3) asks the entity to assess whether it is reasonable and appropriate, implement it if so, and otherwise document why not and implement an equivalent alternative measure if that is reasonable and appropriate (eCFR: 164.306 (read 2026-10-18)).

Step 1. Fetch the rule text at a pinned date and list every item

The rule is 45 CFR Part 164, Subpart C, in the eCFR (eCFR: Subpart C (read 2026-10-18)). The script fetches the XML of the subpart from the eCFR versioner API with the date fixed in the URL, 2026-10-01, so a later amendment cannot change the answer. It sends an Accept-Encoding: gzip header and prints the byte size and the date of the subpart’s latest amendment. The US federal rule text is public.

It reads sections 164.308 (administrative safeguards), 164.310 (physical), 164.312 (technical), 164.314 (organizational requirements) and 164.316 (policies and documentation). In the XML, a standard is a paragraph with an italic “Standard:” label, and an implementation specification is an italic name followed by “(Required)” or “(Addressable)”. The script keeps the paragraph numbering, so each item gets its citation, for example 164.308(a)(3)(ii)(C). These are the two patterns, copied from the script:

std = re.search(r"<I>Standard: ([^<]+?)\.</I>", p)
spec = re.search(r"<I>(?:Implementation specifications?: )?([^<]+?) \((Required|Addressable)\)\.?</I>", p)

One standard, 164.308(b)(1), has no “Standard:” label in the eCFR text, so the script matches its heading by name. Two specifications, in 164.314(a)(2) and 164.314(b)(2), are labeled only “Implementation specifications (Required)”, and the script names them after their standard.

Step 2. Check the list against the rule’s own matrix

Appendix A to Subpart C is a table of the standards and specifications in 164.308, 164.310 and 164.312. The script parses that table separately and compares it with the list from the paragraphs: the same standards, the same number of specifications under each, and the same Required or Addressable letter wherever the matrix gives one. The matrix does not cover 164.314 and 164.316, so those two sections are not cross-checked.

The check found one oddity in the rule text itself: in Appendix A the row for Workforce Clearance Procedure has no (R) or (A) marker, while the paragraph text marks it Addressable. The script prints it and goes on, since the paragraph text is the rule.

Step 3. Write the rating table

This is the judgment, and it is a table, not a model. Each item gets a rating, what a log shows and what it cannot show. The key is the citation and the rule’s own name for the item, so the script can tell if the table and the rule disagree. Three of the 63 rows:

"164.308(a)(3)(ii)(C)": ("Termination procedures", "Partial", "grant history shows when each access ended", "the termination date comes from HR, so on-time needs that record"),
"164.312(b)": ("Audit controls", "Direct", "the platform's access and query history is a mechanism that records activity", "it covers only what the platform records, for as long as it keeps it"),
"164.310(d)(2)(i)": ("Disposal", "None", "", "disposal of hardware or media is physical"),

The full table is in the script and in the CSV. Disagree with a rating and change it: nothing else in the script moves except the counts.

Step 4. Count in DuckDB

The script loads the parsed items, the rating table and the section names into DuckDB tables, joins them, and counts by rating, by safeguard and by the rule’s Required or Addressable label (DuckDB documentation (read 2026-10-18)). Then it runs its own checks and writes the CSV only if all pass.

Run 1: the measurement

We ran the script on 2026-10-18 with DuckDB 1.5.6. The self-check passed: no citation appears twice, the list agrees with Appendix A (18 standards in 164.308 to 164.312), every item has a rating, every key in the rating table matched an item, and the shares add up to 100%.

Command: run 1
python3 guides/hipaa-security-rule-evidence-from-data-platform-logs/hipaa_log_evidence.py --out guides/hipaa-security-rule-evidence-from-data-platform-logs/hipaa_log_evidence.csv
Output from our run 1
duckdb 1.5.6, python 3.12.15
source  https://www.ecfr.gov/api/versioner/v1/full/2026-10-01/title-45.xml?part=164&subpart=C
        bytes=37860 sha256=9041a339ad1eaec5... latest amendment of the subpart=2020-11-24
Appendix A rows with no (R) or (A) marker, where the rule text gives one: ['164.308(a)(3) Workforce Clearance Procedure']

items rated: 63 (22 standards, 41 implementation specifications)

by what                         items  Direct  Partial  None  % with some log evidence
  all items                          63        1       21       41      34.9

by safeguard
  Administrative (164.308)           30        0       14       16      46.7
  Physical (164.310)                 12        0        0       12       0.0
  Technical (164.312)                12        1        5        6      50.0
  Organizational (164.314)            4        0        0        4       0.0
  Documentation (164.316)             5        0        2        3      40.0

by designation in the rule
  Addressable                        22        0        6       16      27.3
  Required                           19        0        7       12      36.8
  Standard                           22        1        8       13      40.9

Direct and Partial items:
  Partial 164.308(a)(1)           Security management process
  Partial 164.308(a)(1)(ii)(D)    Information system activity review
  Partial 164.308(a)(3)           Workforce security
  Partial 164.308(a)(3)(ii)(A)    Authorization and/or supervision
  Partial 164.308(a)(3)(ii)(C)    Termination procedures
  Partial 164.308(a)(4)           Information access management
  Partial 164.308(a)(4)(ii)(A)    Isolating health care clearinghouse functions
  Partial 164.308(a)(4)(ii)(B)    Access authorization
  Partial 164.308(a)(4)(ii)(C)    Access establishment and modification
  Partial 164.308(a)(5)(ii)(C)    Log-in monitoring
  Partial 164.308(a)(5)(ii)(D)    Password management
  Partial 164.308(a)(6)           Security incident procedures
  Partial 164.308(a)(6)(ii)       Response and reporting
  Partial 164.308(a)(7)(ii)(A)    Data backup plan
  Partial 164.312(a)(1)           Access control
  Partial 164.312(a)(2)(i)        Unique user identification
  Partial 164.312(a)(2)(ii)       Emergency access procedure
  Direct  164.312(b)              Audit controls
  Partial 164.312(c)(1)           Integrity
  Partial 164.312(d)              Person or entity authentication
  Partial 164.316(b)(1)           Documentation
  Partial 164.316(b)(2)(i)        Time limit

SELF-CHECK PASSED: 63 items parsed, no citation twice, parsed list agrees with Appendix A (18 standards in 164.308-164.312), every item rated, every rating key matched, shares add up to 100%
wrote guides/hipaa-security-rule-evidence-from-data-platform-logs/hipaa_log_evidence.csv

The result

Rating of all 63 items, by safeguard
SafeguardItemsDirectPartialNone% with some log evidence
Administrative (164.308)300141646.7
Physical (164.310)1200120.0
Technical (164.312)1215650.0
Organizational (164.314)40040.0
Documentation (164.316)502340.0
All items631214134.9
The same items, by the rule’s own label
Label in the ruleItemsDirectPartialNone% with some log evidence
Required (implementation specification)19071236.8
Addressable (implementation specification)22061627.3
Standard (no label)22181340.9

Two things stand out. Every physical and organizational item rates None, because a data platform’s logs do not record doors, hardware or contracts. And only one item rates Direct: audit controls (164.312(b)). The standard asks for mechanisms that record and examine activity. A platform’s access and query history is a mechanism that records it, and people do the examining. Even there the log covers only what the platform records. For the rest, the log is half of the evidence at most.

The 22 items with some log evidence
CitationItemRatingWhat a log showsWhat it cannot show
164.312(b)Audit controlsDirectthe platform's access and query history is a mechanism that records activityit covers only what the platform records, for as long as it keeps it
164.308(a)(1)Security management processPartialaccess and login logs are the records used to detect violationsthe policies, and proof that violations were contained and corrected, are not in a log
164.308(a)(1)(ii)(D)Information system activity reviewPartialaudit logs are the records to be reviewed, and a scheduled review query leaves a run recordwho reviewed what, and what they decided, is a sign-off
164.308(a)(3)Workforce securityPartialgrant history shows who has access to what and when it changedwhether that access is appropriate for each role is a policy decision
164.308(a)(3)(ii)(A)Authorization and/or supervisionPartialaccess history shows what each user readthe authorization or supervision is a manager's record
164.308(a)(3)(ii)(C)Termination proceduresPartialgrant history shows when each access endedthe termination date comes from HR, so on-time needs that record
164.308(a)(4)Information access managementPartialgrant history shows access given and removedthe policies for authorizing access are not in a log
164.308(a)(4)(ii)(A)Isolating health care clearinghouse functionsPartialgrants show whether clearinghouse data is reachable from other roleswhether the separation was designed and approved is a document
164.308(a)(4)(ii)(B)Access authorizationPartialgrant history shows who granted access, to whom and whenthe approval sits in a request or ticket system
164.308(a)(4)(ii)(C)Access establishment and modificationPartialgrant, revoke and role-change records show who changed access and whenthe review the text asks for is a sign-off
164.308(a)(5)(ii)(C)Log-in monitoringPartiallogin history records each attempt, successes and failuresmonitoring and reporting discrepancies needs an alert and a response record
164.308(a)(5)(ii)(D)Password managementPartiallogin history shows which authentication method each login usedpassword rules are a setting, not a log
164.308(a)(6)Security incident proceduresPartiallogs show what happened during an incidentthe procedure is a document
164.308(a)(6)(ii)Response and reportingPartiallogs let a team identify suspected incidents and their reachresponse, mitigation and outcome records are kept elsewhere
164.308(a)(7)(ii)(A)Data backup planPartialif backups run as jobs, job history shows each runthat a copy is retrievable and exact is shown by a restore test, not a log
164.312(a)(1)Access controlPartialgrant history and login history show who can reach the data and who didwhether each person should have that access is not in a log
164.312(a)(2)(i)Unique user identificationPartialthe user list and login history tie every action to a named usera login shared by several people looks like one user
164.312(a)(2)(ii)Emergency access procedurePartialuse of an emergency account shows in login and access historythat the procedure exists and was approved is a document
164.312(c)(1)IntegrityPartialquery and access history show who changed or deleted datawhether a change was improper is not in a log
164.312(d)Person or entity authenticationPartiallogin history records each attempt, the method used and whether it succeededit does not show that the person is who they claim; the identity provider does that
164.316(b)(1)DocumentationPartialan electronic log can be the record of an activity the rule requires to be documentedthe policies and assessments must be documented too
164.316(b)(2)(i)Time limitPartialthe log's own retention period shows how long records are keptthe rule asks 6 years for documentation, and a log's retention is a separate setting

The other 41 items, with the reason each rates None, are in the CSV.

Run 2: plant three faults and see whether the script notices

We ran the same script with three faults planted in the parsed list before the checks: the Termination procedures item listed twice, the name of Audit controls changed to “Audit control”, and the Person or entity authentication standard dropped. Each fault trips a named check:

  • The duplicate trips the check that no citation appears twice and the check that the number of specifications under a standard equals the matrix (4 against 3).
  • The rename trips the check that each key in the rating table meets an item with the same name.
  • The dropped item trips the comparison with Appendix A (a standard the matrix lists and the parsed rule lacks) and the check that every key in the rating table matches an item.

The script reports all five failures, exits with code 1 and writes no CSV. The tables above it are printed from the faulty list, so they are wrong on purpose: they show 63 items, but 21 standards and 42 specifications.

Command: run 2
python3 guides/hipaa-security-rule-evidence-from-data-platform-logs/hipaa_log_evidence.py --out loop-out/planted.csv --plant duplicate-row,renamed-item,drop-item
Output from our run 2
duckdb 1.5.6, python 3.12.15
source  https://www.ecfr.gov/api/versioner/v1/full/2026-10-01/title-45.xml?part=164&subpart=C
        bytes=37860 sha256=9041a339ad1eaec5... latest amendment of the subpart=2020-11-24
Appendix A rows with no (R) or (A) marker, where the rule text gives one: ['164.308(a)(3) Workforce Clearance Procedure']
PLANTED: 'Termination procedures' listed twice
PLANTED: 164.312(b) 'Audit controls' renamed 'Audit control'
PLANTED: 164.312(d) 'Person or entity authentication' dropped from the parsed list

items rated: 63 (21 standards, 42 implementation specifications)

by what                         items  Direct  Partial  None  % with some log evidence
  all items                          63        1       21       41      34.9

by safeguard
  Administrative (164.308)           31        0       15       16      48.4
  Physical (164.310)                 12        0        0       12       0.0
  Technical (164.312)                11        1        4        6      45.5
  Organizational (164.314)            4        0        0        4       0.0
  Documentation (164.316)             5        0        2        3      40.0

by designation in the rule
  Addressable                        23        0        7       16      30.4
  Required                           19        0        7       12      36.8
  Standard                           21        1        7       13      38.1

Direct and Partial items:
  Partial 164.308(a)(1)           Security management process
  Partial 164.308(a)(1)(ii)(D)    Information system activity review
  Partial 164.308(a)(3)           Workforce security
  Partial 164.308(a)(3)(ii)(A)    Authorization and/or supervision
  Partial 164.308(a)(3)(ii)(C)    Termination procedures
  Partial 164.308(a)(4)           Information access management
  Partial 164.308(a)(4)(ii)(A)    Isolating health care clearinghouse functions
  Partial 164.308(a)(4)(ii)(B)    Access authorization
  Partial 164.308(a)(4)(ii)(C)    Access establishment and modification
  Partial 164.308(a)(5)(ii)(C)    Log-in monitoring
  Partial 164.308(a)(5)(ii)(D)    Password management
  Partial 164.308(a)(6)           Security incident procedures
  Partial 164.308(a)(6)(ii)       Response and reporting
  Partial 164.308(a)(7)(ii)(A)    Data backup plan
  Partial 164.312(a)(1)           Access control
  Partial 164.312(a)(2)(i)        Unique user identification
  Partial 164.312(a)(2)(ii)       Emergency access procedure
  Direct  164.312(b)              Audit control
  Partial 164.312(c)(1)           Integrity
  Partial 164.316(b)(1)           Documentation
  Partial 164.316(b)(2)(i)        Time limit
  Partial 164.308(a)(3)(ii)(C)    Termination procedures

SELF-CHECK FAILED: no CSV written
  - 164.308(a)(3)(ii)(C) appears 2 times in the parsed rule
  - 164.308(a)(3): parsed rule has 4 specifications, Appendix A has 3
  - Appendix A lists 164.312(d) (Person or Entity Authentication) but the parsed rule has no such standard
  - RATINGS key 164.312(b) expects 'Audit controls' but the rule says 'Audit control'
  - RATINGS key 164.312(d) ('Person or entity authentication') matches no item in the parsed rule

How to show access was approved and removed on time

This is the second question this page answers, and it is the item pair the ratings say most about. In the table above, Access authorization (164.308(a)(4)(ii)(B)) and Termination procedures (164.308(a)(3)(ii)(C)) are both Partial. The log gives half of each:

  • Given and removed, with times: the platform’s grant history. As one example, Snowflake’s GRANTS_TO_USERS view has a CREATED_ON column for when a role is granted, a DELETED_ON column for when it is revoked (null while the grant is active) and a GRANTED_BY column naming the role that made the grant (Snowflake: GRANTS_TO_USERS (read 2026-10-18)). That view shows which roles a user holds; which data a role reaches comes from the role-level grant views, which we did not check. The page states a latency of up to 120 minutes and gives no retention period.
  • Who actually used the data: the access and login history. Snowflake’s LOGIN_HISTORY covers the last 365 days, with the authentication method and whether each attempt succeeded (Snowflake: LOGIN_HISTORY (read 2026-10-18)). ACCESS_HISTORY records which objects each query accessed, needs Enterprise Edition or higher and covers the last 365 days (Snowflake: ACCESS_HISTORY (read 2026-10-18)).
  • Approved: not in the log. The request and the approver are in your request or ticket system.
  • On time: not in the log either. It is the gap between the grant and removal dates and the dates the policy sets, and the end date of a person’s employment or assignment comes from HR.

So the evidence for the pair is three records joined on the person and the dates: the grant history, the approval and the HR date. We did not run these views. This page measures the rule text, not a platform, and other platforms keep equivalent records under other names.

Method

  • Source: 45 CFR Part 164 Subpart C from the eCFR versioner API, https://www.ecfr.gov/api/versioner/v1/full/2026-10-01/title-45.xml?part=164&subpart=C, 37,860 bytes after decompression in our run; the subpart’s latest amendment is dated 2020-11-24 (from https://www.ecfr.gov/api/versioner/v1/versions/title-45.json?part=164&subpart=C). It is a US federal regulation, public.
  • Unit: one row per standard and one per implementation specification, 63 in all. A standard that has specifications is rated on its own text too, so a rated standard and its rated specifications are separate rows.
  • The rating table is written out in the script and in the CSV, with a reason for each item. The three ratings are defined above.
  • No sampling and no random seed. Every share is a count over the 63 rows.
  • Self-checks, each with the fault that trips it: no citation twice (a duplicated row); the list equals Appendix A for 164.308 to 164.312 (a duplicated or dropped item); every item has a rating (an item the rating table lacks); every key in the rating table matches an item with the same name (a renamed or dropped item); every rating is Direct, Partial or None and the shares add up to 100% (a typo in the table); 63 items against 63 table rows (a duplicate or a drop). The CSV is written only if all pass.

Limits

  • This is not a client result. It rates a public regulation, not any organization’s logs. It does not say what your platform records or for how long.
  • The ratings are our judgment, made by us from the rule text. A reasonable reader could rate some items differently, for example whether a setting counts as evidence (automatic logoff, encryption), whether the login history is enough for person or entity authentication (164.312(d)) or whether a log can be “the record” the rule asks to be documented (164.316(b)(1)). That is why the table is written out.
  • A log is evidence, not proof of compliance. Direct means a log alone is the record of the thing. It does not mean the organization meets the standard, and we do not say what any auditor or regulator will accept.
  • The rule is technology-neutral. It says covered entities may use any security measures that allow them to reasonably and appropriately implement the standards (164.306(b)), so an item rated None here may still be met by a measure that leaves a different record.
  • One item applies only to some organizations. Isolating health care clearinghouse functions (164.308(a)(4)(ii)(A)) applies only to a clearinghouse that is part of a larger organization. We counted it because a log can show part of it.
  • Only Subpart C. We did not rate the Privacy Rule (Subpart E) or the Breach Notification Rule (Subpart D), which also call for records.
  • The source can change. Our numbers are for the version dated 2026-10-01. A later amendment would change the list, and the script would need a new date.

Tested on

Tested on

Platform
DuckDB 1.5.6, Python 3.12, run from Python with the duckdb module
Edition
Open-source DuckDB, in-memory
Date
2026-10-18
Dataset
45 CFR Part 164 Subpart C, eCFR version of 2026-10-01 (US federal regulation, public; source)
Code
hipaa_log_evidence.py, result hipaa_log_evidence.csv

When this is not enough

  • Your platform is not an example here. Find which of your own views hold grants, logins and access, how long they keep them and how late they appear, before you rely on any Direct or Partial rating.
  • A rating is a starting point for a question. It tells you which item needs which second record. It cannot tell you whether the log was on, complete or kept long enough for the period your auditor asks about.
  • The None items are most of the rule. Risk analysis, policies, contracts, training and physical safeguards need their own evidence, from outside the data platform.
  • Legal advice is not here. Whether a safeguard is reasonable and appropriate for your organization is for your compliance and legal team.

Get the grant history, with the approval and the HR date beside it

The platform log shows when access was given and removed. The approval sits in your request system. The termination date sits in HR. Pulling those together by hand is the slow part of an evidence request.

Governance Evidence Pack is a module of Data Control Tower. It is in early access, being built with design partners. We are building it to put the grant history, the approval and the HR end date side by side for the access and termination items this guide rates Partial. It does not cover the other items, and it does not claim compliance.

See the Governance Evidence Pack