Back to BlogSecurity & Compliance

Preventing a Patient-Data Leak: The Engineering Checks

Rupak Amin

Founder & Lead Engineer, RAITHub

8 min read

RAITHub ships and tests production software. See QA as a Service or talk to us.

Most patient-data leaks are engineering failures you can test for before launch: broken object-level access, so one logged-in user can read another patient's record by changing an ID; an exposed API key or missing database rule; sensitive data written to logs or error trackers; and backups or exports left unsecured. Access control is the top risk. Test each with two accounts and the API, not just the screens.

This is general engineering information against OWASP-level risks, not a compliance certification and not a certified penetration test; confirm your legal obligations with your adviser. If you would rather have the checks run for you, see how RAITHub would test this below.

What causes a patient-data leak, in practice?

Leaks rarely come from a sophisticated attacker. They come from a few ordinary mistakes. Broken access control is A01, the top category, in the OWASP Top 10:2025, and its object-level form is the first risk in the OWASP API Security Top 10. The rest are secrets in the wrong place and data copied somewhere unguarded.

Leak vectorWhat goes wrongThe check that catches it
Broken object-level access (IDOR)User changes an ID in the URL and reads another patientTwo accounts; request each other's records via the API
Missing database access ruleA table has no row-level security, so any session reads all rowsCI check that every patient-scoped table has a policy
Exposed secretAn API key or service credential in client code or the repoSecret scanning; inspect the shipped bundle
Sensitive data in logsFull records logged to the console, Sentry or analyticsGrep logs and error payloads for identifiers
Unsecured backup or exportA dump or CSV export readable without authRequest the export URL while logged out

How do I test for the record-swap leak (IDOR)?

This is the single highest-value check. Create two patients, A and B, and confirm A can never reach B's data through any endpoint, even when the screen never offers the option. Test at the API, because the UI hides buttons but the route still answers.

// A deliberate attempt to read another patient's record must fail.
test('patient A cannot read patient B record', async () => {
  const a = await signIn('patient-a@example.test')  // synthetic data only
  const res = await fetch(`/api/patients/${patientB.id}/records`, {
    headers: { cookie: a.cookie },
  })
  // 403 or 404 is correct; 200 with B's data is a leak.
  expect([403, 404]).toContain(res.status)
})

Write the matrix first, then automate the "Refuse" cells. Relationship matters in health apps: a clinician may read their own patients, not every patient.

Action via APIPatient ATreating clinicianOther clinician
Read own recordAllowAllow (own patients)Refuse
Read patient B's recordRefuseOnly if treating BRefuse
List all patientsRefuseOwn panel onlyRefuse
Export recordsOwn only, loggedPer policy, loggedRefuse

The full isolation hunt is in users can see another tenant's data, and the database-level defence is in the PostgreSQL row-level security guide.

What about secrets, logs and backups?

  • Secrets: run secret scanning on the repo and inspect the shipped client bundle. No service key, database URL or provider secret should be reachable from the browser. Keys belong in server environment variables, rotated if ever exposed.
  • Logs and error trackers: grep application logs, Sentry events and analytics for names, record bodies and tokens. A stack trace that includes a full patient object is a leak waiting to be indexed.
  • Backups and exports: request every export and dump URL while logged out, and from the wrong account. A CSV export or a database backup served without auth has leaked the whole dataset at once.
  • Transport: confirm every endpoint is TLS-only and that cookies are secure and HTTP-only.

The broader application checklist is in the vibe-coded app security checklist, which maps cleanly onto any stack, and the full pre-launch version of these checks is in testing a HealthTech app before launch.

Buy, build or hire this?

OptionChoose this whenTrade-off
An automated scanner or SAST toolYou want continuous, cheap coverage of known patternsFinds some issues; misses relationship-based access bugs a human catches
Your own Playwright and SQL suiteA developer can own the IDOR matrix and the RLS CI checkLowest cost; you design the two-account tests yourself
A certified penetration testA customer, regulator or BAA requires a formal attestationNecessary for sign-off; broader and costlier than functional checks
A managed security test or one-off auditYou want access, secrets, logs and backups checked end to endAn outside dependency; it is not a certified assessment

Doing the checks yourself is realistic: plan 1 to 2 days for a developer who can drive the API with two accounts. The main risk of going alone is stopping at the UI, where the missing button hides an endpoint that still answers.

Why RAITHub for this

  • Access boundaries are tested as code. Sundor Skin, a B2B platform RAITHub built, runs a security suite that deliberately tries to read other buyers' data, and CI fails if a buyer-scoped table lacks a row-level-security policy. It has 146 tables and 530+ tests.
  • Health experience, stated honestly. RAITHub has built a healthcare scheduling app for a client; it has not shipped a regulated health product.
  • Honest limits. This is application-level security testing against OWASP guidance. It is not a CREST- or PCI-certified penetration test and produces no compliance attestation. RAITHub holds no SOC 2 or ISO 27001 certification. Production and patient data stay in your own covered cloud; testing uses synthetic data.

When you don't need us

  • Your app holds no patient data and the checks above are overkill.
  • You already have a security engineer running these tests and a scanner in CI.
  • You need a certified attestation or BAA: that requires a certified vendor and your compliance adviser, which RAITHub does not provide.

How RAITHub would test this

  • Scope: a free 15-minute call on the roles, relationships and sensitive data; you confirm you are authorised to have the app tested.
  • Plan: a risk map across access control, object-level authorization, secrets, logs, exports and transport.
  • Test: the IDOR matrix with two accounts per role at the API, secret scanning, log and error-payload inspection, and logged-out export checks, against synthetic data.
  • Deliver: a ranked bug report with reproduction steps and a suggested fix, plus the access tests as automated tests in your repository.
  • What you receive: the report, the tests and a handover note; IP is yours, an NDA is standard. This is engineering QA, not a compliance attestation.

The audit is fixed-price, quoted in writing after the call. See security testing, the HealthTech industry page, and the sibling guide on the audit trail that proves who accessed what. To book it, ask for a security audit.

General engineering information only; it is not a compliance certification. Confirm your obligations with your adviser. Documentation checked on 11 October 2026.

Frequently asked questions

What is the most common cause of a patient-data leak?

Broken access control, where a logged-in user reaches data they should not, most often by changing an ID so they read another patient's record. It is the top category in the OWASP Top 10. Testing it with two accounts at the API, including the explicit refuse cases, catches it before users do.

Does this guide certify my app is compliant or secure?

No. These are engineering checks against OWASP-level risks. They are not a compliance certification, and application-level testing is not a certified penetration test. They reduce real risk and support your programme, but certification is a separate, legal matter decided with your adviser.

Why test at the API instead of the screens?

The screen hides options a user should not have, but the underlying endpoint often still answers. A tester who only clicks buttons never sees the leak; a tester who calls the endpoint directly, with the wrong account, finds it. Always drive the API.

How do secrets end up exposed in a health app?

Usually an API key or database credential placed in client code or committed to the repository, so it ships to the browser or lives in history. Run secret scanning, inspect the shipped bundle, keep keys in server environment variables, and rotate any key that was ever exposed.

Is a missing database access rule really a leak?

Yes. If a patient-scoped table has no row-level-security policy, any authenticated session can read every row once a single query path reaches it. A CI check that fails when a patient-scoped table lacks a policy turns that from a silent risk into a blocked build.

Has RAITHub shipped a regulated health product?

No. RAITHub has built a healthcare scheduling app for a client and has not shipped a regulated health product. For a regulated build, pair its engineering and testing with a compliance partner and a certified assessor.

patient data leakhealthcare data securitybroken access controlowaspphi protectionsecurity testing

Ready to discuss your project?

Book a free 15-minute technical audit with our engineering team.