Introducing the 4-Month AI FrameworkRead the guide

HIPAA and CCPA Aren't Legal Problems. They're Engineering Problems.

Privacy law gets broken in pull requests, not boardrooms. A practical guide to HIPAA and CCPA for engineers: logging, redaction, AI features, cloud guardrails, and what to do when something goes wrong.

Muhammad Usman Siddiqui

Muhammad Usman Siddiqui

Lead AI Architect

· 13 min read

HIPAA and CCPA Aren't Legal Problems. They're Engineering Problems.
On this page · 9 sections
  1. 01TL;DR
  2. 02The two laws, minus the legalese
  3. 03Where it actually shows up in your day
  4. 04Logs are where privacy goes to die
  5. 05AI makes everything a little weirder
  6. 06The cloud won't save you (but it'll help a lot)
  7. 07When something goes wrong
  8. 08The short version I actually keep around
  9. 09Wrapping up

TL;DR

  • Privacy law gets broken in pull requests, not boardrooms. Debug prints, public buckets, stray pixels and unapproved APIs cause most real leaks.
  • HIPAA covers health data in healthcare, including vendors like you. IP addresses, URLs and even "is a patient here" count as PHI. No BAA, no PHI.
  • CCPA covers almost any data about Californians, including ML inferences. People can see, delete, correct and opt out, and you have about 45 days to respond.
  • Logs are the biggest leak. Log IDs and events, never contents. Redact by destination: the same field is full for the clinician, masked in support tools, a placeholder in prompts, and absent from logs.
  • AI gets no exemption. Prompts, outputs, embeddings and caches are regulated data. RAG must enforce permissions in code, and training on PHI needs its own approval.
  • The cloud only covers its half. AWS and Azure give you the controls, but you have to switch them on and lock them in with policy.
  • If something looks wrong, tell security within the hour.

Here's something nobody told me when I started building software that touches health data: the law doesn't get broken in a boardroom. It gets broken in a pull request.

It's a print(request.json()) someone forgot to remove. It's a storage bucket that was "temporarily" public. It's an analytics script on the appointment page that nobody thought about. It's a prompt sent to an LLM API that the company never signed a contract with. None of these feel like legal decisions while you're making them. They feel like Tuesday.

I work as a full-stack AI engineer, and I've spent a fair amount of time around HIPAA and CCPA. What I've learned is that the legal text is long, but the engineering version is surprisingly short. You can carry most of it in your head if someone explains it the way engineers think: data flows, boundaries, defaults, and what happens when things fail.

So that's what this post is. Not legal advice (please talk to your privacy and security folks, they're your friends). Just the stuff I wish someone had sat me down and explained on day one.

The two laws, minus the legalese

HIPAA

HIPAA is about health information in healthcare. If you work for a hospital, clinic, insurer or lab, it applies. If you build software that one of them uses to handle patient data, it applies to you too, because you're a "business associate". Most of us in health tech live in that second bucket.

The thing it protects is PHI: health info that's tied to a person. And "tied to a person" is broader than you'd think. HIPAA lists 18 identifiers, and the obvious ones (name, SSN, phone) are only half the list. IP addresses count. Device IDs count. URLs count. Dates count, except the year. Even the bare fact that someone is a patient at a particular clinic is PHI.

That last one catches people. A mailing list of everyone who booked at an oncology clinic has no diagnosis on it, and it's still PHI.

The part engineers actually live in is the Security Rule. It boils down to: control who gets in, log what they do, encrypt the data, keep it intact, and keep it available. There's also a rule that says once someone in the company knows (or should have known) about a breach, the clock starts. You get 60 days, max, to notify people. If you notice something weird on a Monday and sit on it until Friday, you just spent four of those days.

And one rule I repeat to every new teammate: no BAA, no PHI. A Business Associate Agreement is the contract that lets a vendor touch patient data. Your cloud provider, your email service, your error tracker, your LLM API. If there's no signed BAA covering that exact service, PHI doesn't go there. Full stop.

CCPA

CCPA is California's privacy law, and it's much wider. It's not about health. It's about basically any data that can be linked to a California resident: names, emails, IP addresses, cookie IDs, purchase history, location. It even covers inferences, which matters a lot if you build ML. A churn score or a "likely diabetic" flag attached to a user is personal information.

It applies to businesses above certain size thresholds (roughly $26 million in revenue, or 100,000+ Californians' data, or making most of your money selling data), and it doesn't care where your company is based.

Where HIPAA is mostly about locking things down, CCPA is mostly about giving people control. They can ask what you have on them, ask you to delete it, ask you to correct it, and tell you to stop selling or "sharing" it (sharing here means using it for targeted ads across other sites). You've got 45 days for most requests. If a browser sends a Global Privacy Control signal, you have to treat that as an opt-out. Regulators have fined companies specifically for ignoring it.

How they fit together

People assume that if they're covered by HIPAA, CCPA doesn't apply. It's half true. CCPA steps aside for PHI. But your marketing site visitors, your employees, your non-patient users and your ad pixels are all still CCPA territory. Most health tech companies are living under both at the same time, in different parts of the same system.

The practical move is to stop thinking about two laws and start thinking about one foundation: know your data, collect less of it, encrypt it, restrict it, log access to it, put contracts around it, and be able to delete it. Do that well and you're most of the way there for both.

Where it actually shows up in your day

Compliance isn't a quarterly event. It's fifteen small decisions spread across an ordinary workday, and most of them take seconds if you know to make them.

When a ticket lands. Before writing any code, I ask five questions: what data is involved, where does it go, who sees the result, where does it get stored, and is this a new use of the data? That last one matters. Using intake forms to help a clinician is fine. Using those same forms to fine-tune a model is a completely different conversation, with different contracts and different approvals.

When you're debugging production. This is where good intentions go wrong. Someone needs to see the record, so they export it, paste it into Slack, drop it in a ticket, or worse, into a chatbot. The better path: start with logs and traces (which should only contain IDs), request just-in-time access with a reason when you really need to look, look at the data where it lives, and reproduce the bug with fake data.

When you add a library. That nice front-end error tracker or session replay tool? Many of them capture form inputs, network bodies and full URLs by default. Check what it collects and whether the vendor has a BAA before it ships, not after.

In code review. The three things I catch most often: an endpoint that returns the whole patient object when the screen shows two fields, a debug print left in a handler, and new storage with no encryption or retention rule. None of them are dramatic. All of them add up.

When someone asks for data. "Can I get a CSV of every patient who used the feature?" is a very normal product question. The answer is usually "here's an aggregate dashboard instead", or "here's a de-identified dataset in the analytics environment". Never a spreadsheet in someone's downloads folder.

When a deletion request comes in. This is the real test of whether you know your system. Can you find one person across the database, the search index, the warehouse, the CRM, the email tool and the vector store? Can you delete them everywhere and prove it? If the honest answer is "sort of", that's your next project.

None of this needs a lawyer in the room. It needs habits.

Logs are where privacy goes to die

If I could fix one thing in every health tech codebase, it would be logging.

Logs get shipped to three different vendors. They're read by half the engineering team. They're kept for months. Nobody reviews them. And they're full of request bodies, because logging the whole request was the easiest way to debug that one bug two years ago.

The rule is simple: log events and identifiers, never contents. A good log line looks like this:

summary_generated request_id=8f2c tenant=clinic_41 patient_token=p_7a91 tokens=812 latency_ms=1430

No name. No diagnosis. No prompt. Still completely useful for debugging.

A few things that made the biggest difference for me:

  • Allow-list your log fields. Don't try to scrub "bad" values with regex. You'll miss something. Let the logger emit only the keys you've approved, and drop everything else.
  • Make sensitive values unprintable. Wrap them in a type whose string form is [REDACTED]. Then an accidental log.info(patient) is harmless.
  • Scrub your error tracker. Exception handlers love to attach request bodies and local variables. Turn that off.
  • Keep PHI out of URLs. /patients/{id}/labs in the logs is fine. /search?name=jane&dob=1980-02-14 is a leak waiting to happen.
  • Test it. Send a request with a canary value like CANARY-7731 and fail the build if it shows up anywhere in the logs.

Redact by destination, not by field

This was the mental shift that made redaction click for me. There's no single answer to "do we redact the diagnosis?" It depends on where it's going.

The treating clinician sees it in full; hiding a medication list from a doctor is a safety problem, not a privacy win. The support tool shows it masked, with a "reveal" button that asks for a reason and writes an audit record. The LLM prompt gets the clinical content it needs but the name gets swapped for [PATIENT]. The push notification says "You have a new message from your care team" and nothing else. The logs get none of it.

Same field, five destinations, five different rules. Once you think of it that way, the app-level changes become obvious: per-screen response models instead of serializing whole objects, masking done on the server (not hidden with CSS), a single gateway for all LLM calls, notification templates reviewed like code, and analytics events defined in a schema that CI checks.

And just as important, know what not to redact. Internal IDs and request IDs are how you debug and how audit trails join up. Audit logs need the who, what, when and which record, or they're useless. Data in the database is protected by encryption and access control, not by redaction. You redact on the way out.

AI makes everything a little weirder

Here's the thing about AI and privacy law: there's no special exemption. A prompt is a data flow. An embedding is a data store. A model output about a patient is PHI. A model's prediction about a user is CCPA personal information. Everything you already know still applies. AI just gives data more places to hide.

The places I check on every AI feature:

The prompt. It only gets the fields the task needs. Summarizing symptoms doesn't require the patient's name, address or insurance ID. I swap identifiers for placeholders before the call and put them back after, if the clinician view needs them.

The provider. Is there a BAA, and does it cover this specific model, region and feature? Things like file storage, assistants with saved threads, batch jobs and fine-tuning can have different terms. What's the retention? Is training on our data excluded in the contract, not just on a marketing page?

Retrieval. RAG is a search engine glued to a text generator. If the search ignores permissions, the generator will happily summarize records the user should never see. Filter by tenant and role at retrieval time, in the backend. And please don't rely on a system prompt that says "do not reveal other patients' data". Prompts are not access control.

Embeddings. People treat vector stores as "just numbers". They're not. Embeddings can be partially inverted, and the metadata usually has raw text sitting right next to them. Encrypt them, restrict them, and make sure your deletion job reaches them.

Untrusted input. Any text the model reads, whether a patient message, an uploaded PDF or a web page, can carry instructions. Treat model output as untrusted, give agents the least privilege possible, and restrict where they can send data.

Training. Fine-tuning on PHI is a new use of the data, and it needs its own approval. The safe default is de-identified data, done properly. Removing names isn't de-identification. HIPAA's Safe Harbor method means stripping all 18 identifiers, dates down to the year, ZIP codes down to three digits. Free-text clinical notes are especially hard, because they're full of names, dates and places in places you wouldn't expect. And remember that models can memorize rare strings, so a model trained on identifiable notes can repeat them later. Getting one person out of a trained model is genuinely hard.

Decisions. If the model helps decide who gets care, coverage, a job or a loan, keep a human in the loop. California's newer rules on automated decision-making are starting to require notices and opt-outs for exactly these cases, so loop in your privacy team early.

The cloud won't save you (but it'll help a lot)

"We're on AWS, and AWS is HIPAA compliant." I've heard some version of this more times than I can count. AWS and Azure both sign BAAs, and both give you every control you need. But almost none of those controls are switched on by default, and the provider is only responsible for its side of the line. The data centers, the hardware, the managed service itself: theirs. Your IAM policies, your bucket settings, your network rules, your logging: yours. Nearly every cloud breach in healthcare happens on your side of that line.

What "doing it properly" looks like, in practice:

Draw the boundary with accounts. Put PHI in its own AWS account or Azure subscription. Keep dev and staging separate, with synthetic data only. Send logs to a separate archive account that almost nobody can touch. When the boundary is an account boundary, a dev role literally can't reach production data.

Lock the guardrails. Use Service Control Policies on AWS or Azure Policy with deny effects, set at the organization level, so even account admins can't turn off CloudTrail, make a bucket public, or create unencrypted storage. Then add the same checks to CI so a bad Terraform plan fails the pull request, not the audit.

Identity first. SSO with MFA for every human. No IAM users, no long-lived access keys, no standing admin. Use Identity Center or Entra PIM for just-in-time access. Use OIDC from your CI/CD instead of stored keys.

Encrypt with keys you control. Customer-managed KMS or Key Vault keys on every PHI store, rotated, with key admins separate from the people who read the data. TLS 1.2+ everywhere, including inside your VPC. Encryption has a lovely side effect: under HIPAA, properly encrypted data with a safe key usually isn't a reportable breach if it leaks.

Keep traffic private. No public IPs on databases. Private endpoints for S3, KMS, Bedrock, Blob Storage, Key Vault and Azure OpenAI. And restrict egress, so your PHI workloads can only reach an allow-list. That one control stops a surprising amount, including someone calling an unapproved AI API from inside the boundary.

Log the data access, not just the admin actions. CloudTrail management events are a start, but turn on S3 data events and database audit logs for PHI stores, or the Azure equivalents. When something goes wrong, the question will be "who read what", and those are the logs that answer it.

Back up like ransomware is coming. Immutable backups (AWS Backup Vault Lock, Azure immutable vaults), copied to a separate account, and actually restore-tested. An untested backup is a guess.

When something goes wrong

At some point you'll see something that looks off. PHI in a log that ships to a vendor. A permission bug that let one clinic see another clinic's patients. A bucket that was public for a few hours.

The instinct is to quietly fix it and move on. Don't. Report it to your security team within the hour, even if you're not sure it matters. Contain it if you can do that quickly (revoke the key, flip the bucket private, turn off the feature flag), but don't delete logs or wipe anything, because those are the evidence. Start writing down what you saw and when.

You don't get to decide alone that something "isn't a breach". That call involves a documented risk assessment, and it often comes down to whether your audit logs can prove nobody accessed the data. Which is one more reason to have good audit logs.

The short version I actually keep around

If you skip everything else, keep this:

  • Know which fields are PHI, sensitive, or just personal, and label them in code.
  • Collect only what you need, and send only what each destination needs.
  • No BAA, no PHI. No service-provider contract, no personal data.
  • Encrypt in transit and at rest, with keys you control.
  • SSO, MFA, least privilege, just-in-time production access.
  • Audit-log who touched which record. Never log the record itself.
  • Real data stays in production. Tests use fake data.
  • Every data store has a retention period and a deletion path that actually runs.
  • AI prompts, outputs, embeddings and caches are data stores too.
  • Something looks wrong? Tell security today.

Wrapping up

The longer I work in this space, the less I think of HIPAA and CCPA as rules imposed from outside. They're mostly a written-down version of what good engineering already looks like: clear boundaries, safe defaults, least privilege, observability you can trust, and systems you can actually reason about.

The patients and users on the other side of our databases will never see our code. They're trusting that someone thought about this. Most days, that someone is the engineer writing the pull request.

So collect the minimum, encrypt it, restrict it, log access to it, put a contract around it, and make sure you can delete it. Do those six things, and you're already ahead of most of the industry.

This post reflects my own experience and isn't legal advice. Laws, thresholds and deadlines change, so check the specifics with your privacy and security teams.

Topics

  • hipaa
  • ccpa
  • hipaa compliance for engineers
  • phi logging
  • data redaction
  • ai privacy
  • healthcare ai
Muhammad Usman Siddiqui

Written by

Muhammad Usman Siddiqui

Lead AI Architect

Usman has spent 8+ years building AI and machine learning systems for enterprises. He specializes in LLM architectures, RAG systems, and the data pipelines that keep production AI accurate.

Work with EdgeFirm

Ship this in your stack in 4 to 5 months.

A 30-minute call with the founders who will write your code. Fixed price, full IP ownership, no offshore handoff.

Book Strategy CallOr get the 4-Month Framework
Talk to the founders

Get AI live in months, not years.

Book a 30-minute strategy call with the founders who will write your code.