Back to Blog
|7 min readSecurity Research

Data Flow Mapping · Part 2 of 2

HIPAA and DPDPA Data Flow Mapping in Practice: Two Codebases, One Scan

Same scan, two real codebases, two regulations. What tracing regulated fields through the code actually turns up.

By Scrutora · scrutora.com

Data flow mapping means tracing regulated data, PII, ePHI, payment data, through a codebase to see where it’s stored, logged, and shared, then checking that against whatever framework applies: HIPAA, GDPR, DPDPA, and so on. Part one covered why a map generated straight from code holds up better than one built from memory and interviews, and what manual data subject access request handling actually costs teams that don’t have one. This piece is about what that scan actually turns up in practice, using two real codebases and two different regulatory frameworks.

The first is a mature, open source clinical trial data capture platform: a large, older Java codebase built to manage trial subject records, scanned against HIPAA. The second is a sample seeded healthcare repository, a smaller and newer TypeScript codebase with patient and payment data flows built in for testing, scanned against India’s DPDPA. Different language, different age, different regulation. Same scan both times.

Here’s what the full data flow map looks like on the seeded repo before getting into any one field: eighteen tracked elements on the left, four kinds of sinks on the right, red lines for an unprotected path and teal for an encrypted one.

Complete data-flow map for the seeded healthcare repo, showing eighteen tracked fields connecting to database stores, encrypted stores, application logs, and external transmit
The complete data-flow map for the seeded healthcare repo: every tracked field on the left, every place it lands on the right.

HIPAA Data Mapping: The Clinical Trial Repo

This one only tracks three fields: address (PII), email (PII), and date of birth (ePHI). Three fields sounds manageable until you see where they actually go: all three land in the application log, and date of birth also lands in the database store, unencrypted.

Complete data-flow map for the clinical trial repo, showing address, email, and date of birth flowing into a database store and an application log
The complete data-flow map for the clinical trial repo: three tracked fields, thirteen log sites, one unencrypted store.

Date of birth is the one worth pausing on. It’s written to an unencrypted data store in the part of the codebase that persists subject records, and it’s separately logged in plaintext by the servlet that handles subject updates. Neither finding is alarming by itself. Together they mean the same sensitive field is exposed in two unrelated places, which is a worse position than either finding on its own suggests.

Address and email aren’t stored insecurely, but they show up in logs constantly: address at two locations, email at ten, spread across session handling, logout, and the export jobs that generate study data extracts. Each of those ten email logging sites counts as its own finding.

None of this looks intentional. It reads like what actually happens in older codebases: nobody decided to log PII, it built up one debug line at a time over years of maintenance, in files nobody thinks of as touching regulated data because they’re session handlers and export jobs, not the screen where a patient record gets entered.

There’s a separate problem sitting underneath all of this. The codebase runs on a version of spring-web old enough to carry a critical CVE with no fix listed at all. A dozen vulnerable packages sit on code paths that also handle address and email, so a working exploit against any of them has a direct line to regulated data. The scan marks all of them as import-level exposure, meaning the vulnerable package sits on a module that also touches this data, not call-level, meaning a vulnerable function has actually been shown to run on that path. That’s the difference between “worth reviewing” and “confirmed exploitable,” and it’s the kind of prioritization a CVE list by itself, with no sense of what data is nearby, doesn’t give you.

Blast radius diagram showing a critical spring-web CVE reaching the address and email fields in the clinical trial repo
Blast radius: a critical spring-web CVE with a confirmed path to the address and email fields.

DPDPA Data Mapping: The Seeded Healthcare Repo

This codebase tracks eighteen fields: ordinary PII like name, address, phone, and postal code, ePHI like date of birth, SSN, and medical record number, and payment data like card number and CVV.

The SSN finding is the more interesting one. It’s stored two different ways in the same codebase, encrypted in one module and unencrypted in the main patient data store and its schema. The encrypted path even carries its own critical finding, for weak key management at that same location. This isn’t a case of missing controls. Somebody clearly built encryption for this field, and a separate code path bypasses it. Ask an engineer in an interview whether SSN is encrypted, and the honest answer, based on what the team intended, is probably yes. The scan is picking up the gap between what was intended and what the code is actually doing.

Flow finding for the SSN field in the seeded healthcare repo, showing it stored both in an encrypted module and in two unencrypted data stores
SSN (ePHI): encrypted in one module, unencrypted in the main patient store and its schema — plus a critical weak key management finding on the encrypted path.

The name field runs through a code path flagged as injection-vulnerable, rated critical, which ties a specific application security bug to a specific regulated field instead of leaving it as a generic line item on a vulnerability list with no connection to what data it touches.

The external recipients matter here too, and this is where a future data subject access request gets easier to answer rather than harder. Segment gets email, full name, and phone for analytics. SendGrid gets email, first name, and last name for communications. Stripe gets credit card, CVV, and email for payments. That’s the standard “who have you shared my data with” answer, and normally it comes from someone recalling which vendors are wired up and then checking that against the code by hand. Here it’s already sitting in the same output as the rest of the map, tied to exactly which fields each vendor gets.

Table of external recipients receiving personal data from the seeded healthcare repo, mapped to Article 30 categories and applicable frameworks
External recipients, tied to exactly which fields each one receives — the Article 30 answer, generated instead of recalled.

The dependency findings are where prioritization matters most. One version of lodash carries a critical CVE that reaches ten different regulated fields at once: SSN, medical record data, and most of the PII in the store. A single version bump resolves it. A separate, older version of axios carries a run of high and medium severity CVEs sitting between regulated data (card number, CVV, email, name, phone) and all three external recipients, meaning a compromise of that one HTTP client has a plausible path to data already flowing out to Stripe, SendGrid, and Segment. Most of the dependency advisories in this codebase land on a path that touches regulated data, and every one of them already has a fix version identified. Finding the CVEs was never the hard part. Knowing which ones actually mattered was.

Blast radius diagram showing a critical lodash CVE reaching ten regulated fields in the seeded healthcare repo, including SSN and medical record data
Blast radius: a single critical lodash CVE with a confirmed path to ten regulated fields, including SSN and medical record data.

What Data Flow Mapping Across Two Frameworks Has in Common

These two codebases don’t have much in common on the surface: one’s a mature, monolithic Java application built for clinical trials, the other’s a small modern TypeScript service seeded with realistic healthcare and payment data for testing. The scan treated them the same way. Tag the sensitive fields, trace them through the code to wherever they land, and check that path against known vulnerabilities sitting on it.

Swapping the framework, HIPAA on one, DPDPA on the other, changed what counted as regulated and which findings applied, but it didn’t require redoing the underlying trace.

That’s really the point of building the map this way. The same flow graph can be checked against more than one regulation, and re-checked the moment the code changes, instead of getting re-interviewed the next time an audit or a data subject access request forces the question. Part one covers what that re-interviewing actually costs when the map isn’t kept current.

Vimalendukumar Dwivedi is Co-founder of Scrutora, a Code Compliance Platform.

See what this scan finds in your own codebase

Scrutora traces regulated fields end to end, storage, logs, and third-party recipients, and ties every CVE to the specific fields it can actually reach.

Share this article