A security-hardening checklist for self-hosted Apache Fineract

6/14/2026

A security-hardening checklist for self-hosted Apache Fineract

Fineract runs your ledger. It holds client PII, account balances, and the API that moves money, which makes it exactly the kind of system attackers go looking for. And the project is blunt about whose job it is to protect: in its own words, you are responsible for securing your production instances.

People sometimes read Fineract's list of past CVEs and get nervous. They have it backwards. A mature project with a formal security process that finds, discloses, and fixes vulnerabilities is behaving exactly as it should, and every other piece of serious software has the same list. The useful way to read that history is as a map. It tells you precisely where Fineract has been weak, which tells you precisely what to harden first. We run managed Fineract, so we do this for every instance. Here is the checklist.

What the CVE history actually tells you

Fineract has published roughly twenty CVEs over the years, and they cluster into a handful of patterns. By far the largest is SQL injection, usually through search and reporting query parameters: a long line of them, including a critical one fixed as recently as the 1.10.x series. After that come a file-upload path-traversal that allowed remote code execution, a few authentication and authorization gaps including a privilege escalation to super-user and an access-control bypass in the self-service API, a server-side request forgery, and a handful of transport and credential problems, including a stretch where HTTPS hostname verification was silently disabled.

Two things stand out. First, almost every one of these is reachable by an authenticated, low-privilege user hitting the API. That means the most valuable thing you can do is shrink the set of people who can reach the API at all, and treat every account as a potential attacker. Second, the fixes ship in the latest release, and Fineract has no long-term-support branch. The moment a new version comes out, the previous ones are effectively end of life. Staying on a comfortable old release is not a security posture; it is a backlog.

So the checklist below is ordered roughly by leverage. If you do the first few things and nothing else, you have closed most of the real risk.

A defence-in-depth diagram for self-hosted Fineract, shown as stacked layers from the outside in. 1, network perimeter: reverse proxy, IP allowlist, private database subnet, block the actuator. 2, TLS: a real CA certificate, HTTPS only with HSTS. 3, authentication: kill the default credentials, OAuth2 with two-factor, least-privilege roles, maker-checker. 4, the instance: disable the test profile, keep secrets out of config, drop the demo data. 5, database: least-privilege user, encrypted tenant credentials, isolated tenants. At the centre, Fineract and the money and PII it protects. Underneath all of it: stay on the latest release, because the CVE cadence never pauses.
Hardening as layers. Each one shrinks what an attacker can reach, and staying patched holds the whole stack up.

1. Keep it off the internet

This is the single highest-value control, and it is the project's own first recommendation: do not run Fineract directly on the internet. The official guidance is explicit that IP filtering and similar techniques may be essential for all API ingress.

  • Put Fineract behind a reverse proxy or API gateway. Nothing should talk to the Fineract provider port directly from the public internet.
  • Allowlist by IP for admin and back-office traffic, so the management surface is not reachable from anywhere.
  • Put the database on a private subnet with no route to the internet, and restrict the instance's outbound traffic too. Egress filtering is what blunts a server-side request forgery: even if an attacker tricks the server into making a request, it cannot reach anything useful.
  • Do not expose the Spring Boot actuator endpoints publicly. Health checks belong on the internal network, not on the open API.

2. Real TLS, properly

Fineract ships with a self-signed development certificate, and there was a real CVE in its past where hostname verification was disabled outright, which quietly allowed man-in-the-middle attacks. Transport security has to be real, not just switched on.

  • Replace the bundled self-signed certificate with one from a real certificate authority. Point Fineract at your own keystore with FINERACT_SERVER_SSL_KEY_STORE and FINERACT_SERVER_SSL_KEY_STORE_PASSWORD, and change the default keystore password.
  • Serve HTTPS only and turn on HSTS (FINERACT_SECURITY_HSTS_ENABLED) once you are on public HTTPS.
  • Encrypt the hop from the application to the database too, not just the public edge.
  • Stay on a current release, which closes the old transport-verification bug by default.

3. Kill the defaults and lock down access

A fresh Fineract has a well-known default login, mifos / password, and the demo tenant ships with seed data. Several of the auth-related CVEs were about privilege escalation and access-control bypass, so this layer matters.

  • Change the default mifos / password credentials on every tenant before you let anyone, or anything, connect. Our getting-started guide walks through it.
  • Move off HTTP Basic auth. Fineract supports an OAuth2 profile you can point at an identity provider like Keycloak: set FINERACT_SECURITY_OAUTH_ENABLED on and FINERACT_SECURITY_BASICAUTH_ENABLED off.
  • Turn on two-factor authentication (FINERACT_SECURITY_2FA_ENABLED) for the people who can move money or change configuration.
  • Grant least-privilege roles. Do not hand out super-user because it is convenient; the privilege-escalation history is exactly why fine-grained roles exist.
  • Require maker-checker, the four-eyes principle, on the operations that matter: loan approval, disbursement, write-off, journal posting, and role changes. It is built in, and it doubles as an audit record of who did what. See our maker-checker guide.
  • Restrict CORS. The default allowed-origin pattern is a wildcard; set FINERACT_SECURITY_CORS_ALLOWED_ORIGIN_PATTERNS to your own front-end domains.

4. Harden the instance itself

The convenience build is meant for getting started, not for production, and it leaves a few things on that should be off.

  • Disable the test Spring profile. It is enabled in the sample Docker setup, and the project says plainly it must not be on in production.
  • Keep secrets out of config files and images. Database passwords and keys belong in environment variables or a secret manager, never committed and never baked into an image.
  • Run the container as a non-root user on a restricted filesystem. The file-upload path-traversal CVE is the reason the blast radius of the process matters.
  • Remove the demo tenant and its seed data before go-live.

5. Give the database the least privilege it can do its job with

The default database credentials are as well-known as the application ones, and tenant database passwords are stored in Fineract's tenant registry.

  • Use a scoped database user, not root. The defaults (FINERACT_DEFAULT_TENANTDB_UID and FINERACT_DEFAULT_TENANTDB_PWD) are root / mysql; replace them with a strong, limited user whose rights are scoped to the Fineract databases only.
  • Set the tenant master password (FINERACT_DEFAULT_TENANTDB_MASTER_PASSWORD) before any data is written, so the stored tenant credentials are encrypted at rest rather than sitting in plaintext. The details are in our multi-tenancy guide.
  • Encrypt connections to the database and the storage underneath it.
  • Keep tenants in separate databases, which is how Fineract isolates them, and back the whole thing up with a restore you have actually tested.

6. Stay patched, because this one never stops

Given that the CVE history is dominated by SQL injection and that fixes only land in the latest release, keeping current is not housekeeping, it is the control. A recent release also added a built-in SQL validator that catches most injection attempts at the source.

  • Track Fineract security advisories. They go out through the project's security@ channel and the usual Apache announcement lists.
  • Upgrade promptly to the latest release. Because there is no supported old branch, a critical fix effectively forces the upgrade, so plan for it rather than being surprised by it. We costed that ongoing work out in the self-hosting breakdown.
  • Scan your dependencies and images. Fineract is a large Spring application, and some of its worst historical bugs came from upstream libraries, not Fineract's own code.
  • Be careful with custom report and datatable SQL. User-authored queries are a classic injection path, so restrict who can write them.

7. Assume something will get through, and watch for it

No checklist is perfect, so the last layer is detection.

  • Use Fineract's audit trail. Every state-changing command is recorded, and with maker-checker on, you capture both the maker and the checker. You can query it through the audit API.
  • Ship application and access logs to somewhere central, because Fineract does not aggregate them for you, and turn on client-IP tracking (FINERACT_CLIENT_IP_TRACKING_ENABLED) so the audit log records where requests came from.
  • Alert on the suspicious patterns: bursts of failed logins, access from unexpected places, spikes in error responses. Most of the probing that precedes a real breach shows up here first.

If you only do five things

The full list is worth working through, but if you are triaging, this is the order that closes the most risk for the least effort:

  1. Keep Fineract off the public internet, behind a proxy with IP allowlisting and a private database.
  2. Stay on the latest release.
  3. Change every default credential and put a real, verified TLS certificate in front.
  4. Move to OAuth2 with two-factor, and require maker-checker on anything that touches money.
  5. Run the database with a least-privilege user, encrypt the stored tenant credentials, and turn off the test profile.

So, what should you do?

Security hardening on a self-hosted Fineract is the same kind of work as the rest of running it: unglamorous, never finished, and entirely yours. The checklist above is not a one-time project you complete and forget. It is a standing requirement, because the CVE cadence does not pause, the dependency advisories do not stop, and the patches do not apply themselves. The production guide covers the operational side of the same coin, and the production-readiness post covers why all of this is yours to own.

That is the part we take off your plate. Finecko runs managed Apache Fineract with the perimeter, the TLS, the auth, the least-privilege database, and the patching handled, and we track the security feeds and apply fixes on our schedule so a new CVE is our problem and not your weekend. If you would rather run it yourself, treat the list above as a recurring operational discipline, and you will have closed the doors that actually get used.

Skip the ops. Run managed Apache Fineract.

Finecko runs managed Apache Fineract for you - the Finecko Hub, the right topology, connection pooling, backups, TLS, patching, and on-call. You get the open-source core without the operations, and the free plan is a full environment to try with no credit card.