v2.142
What's Changed
Security
- EST
/cacerts,/simpleenroll,/simplereenroll,/serverkeygen,/csrattrsnow enforceest_enabledon every request and short-circuit with503 EST disabledinstead of falling through to the SPA. The/serverkeygenbody is also size-capped and stricter about content negotiation. - EST and SCEP mTLS client certificates are only honoured when the request comes from a trusted reverse proxy (
security.trusted_proxies). Direct hits without TLS termination by UCM no longer accept proxy-injected client cert headers. - mTLS login route gated behind trusted-proxy check. Same protection as EST/SCEP — header-based mTLS is rejected unless the request originates from a trusted proxy.
- 2FA backup codes are now hashed at rest (Argon2id) and consumed atomically; plaintext codes are returned only at generation time and never stored.
- Approval quorum is race-safe and idempotent. Concurrent approvals on the same request can no longer over-approve; double-submits are deduplicated.
- On-demand CRL generation is serialised per-CA with a per-CA lock and
503 Retry-After: 5under contention — closes a CPU/IO DoS vector when many clients hit/cdp/<ca>.crlsimultaneously. - Outbound webhooks revalidate the resolved IP at delivery time (DNS-rebinding window closed) and reject cloud-metadata IPs (
169.254.169.254, GCP/Azure/Alibaba equivalents) and loopback. RFC1918 /.lan/.localtargets remain allowed by design (UCM is on-prem). - SSO/IdP, ACME proxy and webhook URL fields all share the same SSRF helper (
validate_url_not_cloud_metadata) — cloud metadata is blocked everywhere. - CSV bulk user-import capped at 5 MB / 10 000 rows with
413on overflow. - Runtime HSM
pip installdisabled by default, returns403with a hint to setUCM_ALLOW_RUNTIME_PIP=1or install the dependency via the system package manager. - SCEP CSRs no longer copy arbitrary KU/EKU bits — only a whitelist (
digitalSignature,keyEncipherment,serverAuth,clientAuth) is honoured. - SCEP RFC 8894 P0/P1/P2 hardening — stricter PKCS#7 parsing, transaction-ID validation, signed/encrypted response envelope checks; iOS/macOS enrollment fixes (#102).
- ACME account private keys encrypted at rest with the application key.
- Password change endpoint ignores client-supplied
force_change(only operators can clear that flag). - CSRF token entropy increased; password hash algorithm tightened; database migration identifiers validated against an allow-list.
ProxyFixis opt-in viasecurity.trusted_proxies— prevents unauthenticatedX-Forwarded-Forspoofing on direct deployments.- Filesystem session directory is now created/enforced at mode
0o700and the application refuses to boot if it has group/world-readable bits. - EST audit lines use the trusted-proxy-aware client IP instead of the raw socket address.
Added
utils/trusted_proxy.py— sharedis_request_from_trusted_proxy()/client_ip()/reject_untrusted_proxy_headers()helpers used by EST, SCEP, mTLS login and audit.utils/ssrf_protection.py— single source of truth forvalidate_url_not_cloud_metadataandvalidate_host_not_cloud_metadata, used by webhooks, SSO, ACME proxy, OPNsense import.utils/safe_commit.py,utils/require_json_body,utils/parse_request_pagination,utils/safe_call,utils/audit_event— small composable helpers applied acrossapi/v2/*to remove boilerplate and silence intermittent rollback bugs.useCRUDPagefrontend hook covering 4 list/create/edit pages.
Changed
- Massive backend modularisation.
system.py(1556 l),certificates.py(2220 l),cas.py(1245 l),ssh_cas.py(1607 l),database_admin(817 l),discovery_service,pdf_generator,scep_service(981 l),acme_service(1456 l → 7 mixins ≤350 l),trust_store(1487 l),ca_service(788 l),restore_mixin,notification_service,audit_service,crl_service,ssh_cert_service,msca_service,account.py,acme.py,tools.py,acme_client.py,users.py,settings.py,opnsense_importandmodels/__init__.pywere split into focused submodules. Behaviour is unchanged; module size, test isolation and review surface improve. - Frontend modularisation.
CAsPage,CertificatesPage,DiscoveryPage,ACMEPage,SettingsPageandSsoProviderFormsplit into per-section sub-components underpages/<feature>/. - All
api/v2/*db.session.commit()calls now go throughsafe_commit()— consistent rollback + error logging on every write path.
Fixed
- PKCS12/PFX export now honours the
include_chainflag (#100). Previously the CA chain was always included, regardless of the request. - Dashboard chart cards no longer overflow the grid and System Health gained an internal scrollbar (#99).
- iOS/macOS SCEP enrollment regressions (#102).
Internal
- ~20 test files de-duplicated against
conftest.py; pre-commit i18n + 461 frontend + 1613 backend tests gate every commit. - RC validated end-to-end on Debian (
pve:8445), Fedora (fedor:8443) and Docker (pve:8444): smoke API 8/8 and Playwright use-cases 10/10 on all three targets.
📜 Recent release history (last 2 versions)
[2.141] - 2026-04-29
Fixed
- Admin lockout prevented on database backend switch (#96). Switching the database backend (SQLite ↔ PostgreSQL) no longer locks the admin out. Boolean and JSON columns are now coerced correctly when migrating rows from SQLite to PostgreSQL, the migration runs per-table in its own transaction so a single bad row no longer aborts the whole switch, and the active admin session survives the cutover.
- PostgreSQL backups via
pg_dump. The Docker image now shipspostgresql-client, so PostgreSQL-backed instances can produce nativepg_dumpbackups during backend migrations and scheduled backups.
Changed
- In-app help covers v2.128–v2.140 features in English plus all 8 translated languages (fr, de, es, it, ja, pt, uk, zh).
- README features and roadmap refreshed for v2.128 → v2.140.
Internal
- CI: backend test collection no longer fails on missing
SECRET_KEY/JWT_SECRET_KEY— workflow now exports test-mode env vars before pytest runs.
[2.140] - 2026-04-27
Fixed
- Certificate SAN database columns now derived from the final SAN list (#94). When a CN is auto-promoted to an
rfc822NameSAN at issuance, thesan_email/san_dns/san_ip/san_uricolumns are now written from the canonical SAN list instead of the raw form payload, so DB queries match the X.509 extension. Migration027_backfill_san_emailre-parses existing certificate PEMs and backfills any rows that were out of sync (idempotent on SQLite and PostgreSQL). Thanks @Hemsby. - Certificate and CA files written to disk on creation (#95). Added SQLAlchemy
after_insertlisteners on theCertificateandCAmodels that immediately materialize.crt/.keyfiles underdata/certs/anddata/cas/for every creation path (UI, CSR signing, ACME, SCEP, import). The startup file-regeneration scan is kept as a safety net. File-write errors are logged but never abort the database transaction. Thanks @Hemsby.
Full history: CHANGELOG.md
Installation
Docker (Recommended)
# From Docker Hub
docker pull neyslim/ultimate-ca-manager:2.142
# Or from GitHub Container Registry
docker pull ghcr.io/neyslim/ultimate-ca-manager:2.142
# Run
docker run -d -p 8443:8443 \
-e SECRET_KEY=$(openssl rand -hex 32) \
--name ucm neyslim/ultimate-ca-manager:2.142Debian/Ubuntu
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.142/ucm_2.142_all.deb
sudo dpkg -i ucm_2.142_all.deb
sudo apt-get install -fFedora/RHEL
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.142/ucm-2.142-1.fc43.noarch.rpm
sudo dnf install ./ucm-2.142-1.fc43.noarch.rpmSilent/Automated Install
# Skip firewall prompts for CI/automation
sudo UCM_PORT=8443 UCM_FIREWALL=no dpkg -i ucm_2.142_all.debDefault Credentials
- Username:
admin - Password:
changeme123
Change the password immediately after first login!