Installing Community Plugins
Community plugins extend ChurchCRM with third-party integrations. Every community plugin has been reviewed by the ChurchCRM maintainers and is listed in a checksum-pinned allowlist — ChurchCRM refuses to install anything that isn't on that list. This page walks you through the install flow and explains what each safety check is doing for you.
Before you install anything new, read Plugin Security & Compliance so you know how to interpret the risk level you'll see on the install screen.
Who can install plugins?
Only ChurchCRM users with the Admin role can install, enable, or
configure plugins. The installer calls the admin-only API routes under
/plugins/api/…, which are guarded by
AdminRoleAuthMiddleware at the server level.
Step 1 — Review the approved list
From Admin → Plugins → Browse community plugins, or directly via the API:
curl -s -H "x-api-key: $ADMIN_API_KEY" \
https://your-crm.example.org/plugins/api/approved | jq
Each entry shows:
- Name and version
- Risk level —
low,medium, orhigh - Risk summary — one sentence explaining the worst thing the plugin is allowed to do
- Permissions — the capability tags the plugin declared
(
network.outbound,secrets.store,hooks.person, etc.) - Minimum ChurchCRM version
- Reviewed-at date
- Homepage, author, and optional notes
If the risk level or risk summary make you uncomfortable, don't install the plugin. You can always file a question with the maintainers first.
Step 2 — Install
From Admin → Plugins, click Install next to a plugin in the approved list, or POST to the install API directly:
curl -s -X POST \
-H "x-api-key: $ADMIN_API_KEY" \
-H "content-type: application/json" \
-d '{"downloadUrl":"https://example.org/releases/example-plugin-1.0.0.zip"}' \
https://your-crm.example.org/plugins/api/plugins/install
ChurchCRM runs a pipeline of safety checks. Every one must pass, in order:
- Allowlist check. The
downloadUrlmust match an entry insrc/plugins/approved-plugins.jsonexactly. Anything else is refused. - Version check. If the entry declares
minimumCRMVersion, your installed ChurchCRM version has to meet it. - Duplicate check. If
src/plugins/community/{id}/already exists, the install is refused — plugins are never overwritten. Disable and remove the current copy first to upgrade. - HTTPS download. ChurchCRM downloads the zip using cURL with TLS verification, follows at most four redirects (HTTPS only), and aborts if the transfer exceeds 20 MB.
- Checksum verification. The downloaded bytes' SHA-256 is compared
to the
sha256in the registry. If they don't match byte-for-byte, the install is refused before the archive is even opened. This protects you against a compromised mirror or a man-in-the-middle attack. - Archive validation. The zip is walked entry by entry, refusing
ZIP Slip attempts (
.., absolute paths, drive letters), unsafe extensions (.phar,.phtml,.sh,.exe,.so,.dll), symlinks, and hidden files other than.editorconfig/.gitattributes. The archive must contain exactly one top-level directory named for the plugin id. - Size sanity. Total uncompressed size is capped at 80 MB and entry count at 2000 to block zip bombs.
- Manifest cross-check. After extraction,
plugin.jsonmust declare the sameid,version, andtype: "community"as the registry entry.
Only once all checks pass does the new directory appear under
src/plugins/community/{id}/. Any failure is logged with a short,
actionable error message.
Step 3 — Review the extracted files
The installer does not auto-enable the plugin — this gives you one more chance to inspect what was extracted before it runs on your server.
ls src/plugins/community/{id}
cat src/plugins/community/{id}/plugin.json
Look for:
- A
plugin.jsonthat matches the registry entry. - A
src/directory with a single main class file. - Optional
routes/,views/,locale/, andhelp.jsonfiles. - Nothing else — no stray config files, no credentials, no embedded binaries.
Step 4 — Enable
From Admin → Plugins, click Enable on the newly installed plugin. ChurchCRM will:
- Re-check that the plugin's
dependenciesare met. - Re-check the ChurchCRM version.
- Call the plugin's
activate()hook. - Start loading its routes on subsequent requests.
If the plugin exposes settings (API keys, default values), fill them in now. Password fields are masked — entering nothing leaves the stored value in place.
Step 5 — Test
Every plugin with a hasTest: true manifest has a Test Connection
button on its settings page. Click it before relying on the plugin in
production — it calls testWithSettings() with the current form values
and either confirms success or returns the upstream error message.
Installing a plugin not on the approved list
Two buttons live next to the community plugin header: Browse Approved (the vetted list) and Install from URL. Use "Install from URL" when:
- You are the plugin developer testing a build before submitting it to the approved list.
- You are running a private plugin that will never be published publicly (custom integrations for one parish).
- You need to run an experimental plugin that isn't ready for allowlisting yet.
The Install from URL modal requires three things:
- Plugin zip URL — HTTPS only, ideally an immutable release artifact (GitHub release asset, versioned S3 object).
- SHA-256 — the plugin author must publish this alongside the release. ChurchCRM refuses the install if the bytes don't match.
- Plugin id — must match the top-level directory in the zip and the
idfield inplugin.json.
The installer runs the same hardening pipeline as the verified path — the only difference is that the URL does not have to be on the approved list.
The resulting plugin is flagged as unverified everywhere in the admin UI with a yellow banner and no risk/permissions panel. You can still enable it, but you accept responsibility for whatever it does.
If you install an unverified plugin and the URL later appears in the approved list (same URL, same SHA-256), the installer silently short-circuits into the verified path on the next install attempt.
Deleting a community plugin
Click the trash icon on any community plugin card to uninstall it. This is also the upgrade path — the installer refuses to overwrite an existing directory.
The uninstall flow:
- Refuses core plugins (they can only be disabled).
- Calls the plugin's
deactivate()anduninstall()lifecycle hooks. - Deletes
src/plugins/community/{id}/from disk. - Clears every
plugin.{id}.*row from the config table, including stored credentials.
Re-installing the same plugin is a clean-slate install, not an upgrade.
If a plugin is quarantined
If a plugin throws while loading or booting, ChurchCRM automatically quarantines it:
- Its card shows a yellow "Quarantined" badge and border.
- It stops running immediately — even with
enabled=1it will not load. - The card banner shows the exception message.
- You cannot re-enable it until you explicitly clear the quarantine.
Typical causes: a missing PHP extension, a syntax error after an upgrade, or a revoked registry entry. Fix the underlying issue, then click the shield icon on the plugin card to clear the quarantine.
Troubleshooting
Install was refused with a checksum error. Someone tampered with the download mirror, or the upstream maintainer republished the artifact without bumping the version. Report it to the ChurchCRM forum and do not retry.
Install was refused because the plugin is "already installed".
Disable the current copy from Admin → Plugins, delete
src/plugins/community/{id}/, and re-run the install.
The plugin installed but Enable fails with a dependency error.
Check the plugin's dependencies list — another plugin needs to be
installed and enabled first.
A plugin is quietly misbehaving. See Plugin Security & Compliance → Compliance scan for the audit commands to run against an installed plugin.
A plugin disappeared from the approved list. The ChurchCRM maintainers revoked it, usually because of a disclosed vulnerability. Disable it immediately and wait for a fixed version to re-appear.