📜 Recent release history (last 2 versions)
[2.184] - 2026-07-05
Added
- Configurable RFC 5280 CA profile — the Create CA wizard exposes signature digest (Auto aligns P-384 to SHA-384 and P-521 to SHA-512, or explicit SHA-256/384/512) and an expandable Certificate Profile section with Key Usage and Extended Key Usage. Roots default to
keyCertSign+cRLSign(nodigitalSignature) and no EKU; issuing CAs adddigitalSignatureand optionalserverAuth, matching common enterprise root/intermediate profiles (Let's Encrypt Root-YR / issuing CA style). Intermediate CAnotAfteris clamped to the parent CA expiry, andGET /api/v2/cas/:idnow returns the X.509 serial number (colon-separated hex) and SHA-1/SHA-256 thumbprints. The obsolete Create CA help step about optional template selection (templates removed in migration 017) has been removed (#160). - ACME external CSR and renewal key reuse — the ACME request form now offers a Key Source selector: Generate new key (default), Reuse key on renewal (preserves the same private key across renewals for DANE/TLSA and key pinning; first issuance generates a key, renewals reload it), or Provide external CSR (paste a PEM CSR; UCM submits it at ACME finalize, the private key never enters UCM). CSR domains are validated against the order identifiers (case-insensitive, RFC 4343). Auto-renewal honours the selected key source. Migration
049addskey_source,csr_pemandsource_certificate_idonacme_client_orders(#161). - ACME staging preflight dry-run — a Run Preflight action on the ACME request form validates domains, contact email, ACME account/EAB, CA connectivity and DNS-01 challenge setup against the Let's Encrypt staging directory without consuming production rate limits or changing the global environment. Two modes: Full (staging order + required DNS TXT records preview) and Validate only (config + connectivity). For manual DNS providers it displays the exact
_acme-challengeTXT records to add, with optional DNS propagation verification. Emits anacme.preflightwebhook event and anacme_preflightaudit entry (#162). - Typed SAN validation for CSR creation — SAN entries are now validated per type (DNS, IP, Email, URI, UPN) on both backend and frontend, with clear cross-type errors (e.g. an FQDN entered in the IP field is rejected with a hint to use DNS). The frontend validation mirrors the backend rules so the client and server stay consistent (#167).
- NIST P-521 EC curve option and normalized EC key labels — Generate CSR and Create CA now accept NIST P-256, P-384 and P-521 (ECDSA) key types through normalized labels (
EC P-256,NIST P-384,secp256r1,prime256v1, …) that map to the OpenSSL curve names used internally. PreviouslyEC P-256failed because the UI label was stripped toP-256and validated against OpenSSL curve names. Thesecp256k1(Koblitz) curve remains intentionally unsupported (#167). - Hex serial number in certificate technical details — the certificate details view shows the serial as colon-separated uppercase hex (browser/OpenSSL display style) alongside the decimal form, copyable. Conversion handles decimal,
0x-prefixed and compact/colon hex inputs and supports serials larger than 159 bits via arbitrary-precision integer math.
Fixed
- API key permission escalation — a non-admin user with permission to create API keys (
POST /api/v2/account/apikeys) could mint a key carrying permissions their own role did not hold (e.g. a viewer grantingadmin:system). The create path now rejects any permission the creator does not have, with the same wildcard semantics as the auth checker. Sharing a wildcard key (*) requires the creator to be an admin (#163). - Forged mTLS enrollment via spoofed proxy headers —
POST /api/v2/mtls/enrollhonoredX-SSL-Client-Verify,X-SSL-Client-S-DNandX-SSL-Client-Certheaders from any peer, so a caller who could reach gunicorn directly could forge a client certificate and enroll it as another user. The endpoint now gates onis_request_from_trusted_proxy()for those headers, matching the existing protection on thelogin_mtls()path (#163).
[2.183] - 2026-07-03
Added
- Operator-configurable HSTS (Strict-Transport-Security) header — the HSTS policy was previously hardcoded to
max-age=31536000; includeSubDomainson every HTTPS response. Instances serving self-signed certificates during initial setup can now opt out entirely, drop theincludeSubDomainsdirective, or shortenmax-agefrom Settings → Security. The setting can also be forced viaUCM_HSTS_ENABLED,UCM_HSTS_INCLUDE_SUBDOMAINSandUCM_HSTS_MAX_AGEenvironment variables in/etc/ucm/ucm.env(takes precedence over the database); when set, the corresponding toggle in the UI is locked with a badge (#154). - mTLS PKCS#12 export from Account — after generating an mTLS certificate from the Account page, both PEM and PKCS#12 (.p12) download are now offered client-side, with password-protected PKCS#12 for browser or OS keychain import. The download endpoint enforces POST with a JSON body for PKCS#12 (password never sent via query string, avoiding leakage in proxy logs), minimum 8-character password, and returns the
AuthCertificateid usable by list/download/export (#156).
Fixed
- WebSocket handshake fails when if HTTPS_PORT was set to 443 -
CORS_ORIGINSalways appended:{HTTPS_PORT}to every allowed origin, so on port 443 the list contained entries such ashttps://ucm.example.com:443. Browsers omit the port number from theOriginheader when it is the scheme default so it would never match. As Socket.IO performs server-side checks onOrigin, WebSocket connections would be silently rejected.CORS_ORIGINSnow omits the port suffix whenHTTPS_PORTis 443 (#155). - SSH setup script command injection via hostname — the public
GET /ssh/setup/<refid>endpoint accepted arbitraryhostnamequery values that were embedded into generated shell/PowerShell scripts without validation. A payload such as$(id)or";id;"would execute when an operator piped the script to bash. Hostnames are now validated against^[a-zA-Z0-9._-]+$via a shared helper on both the public and authenticated setup routes, and the Windows script generator escapes single quotes (#157).
Full history: CHANGELOG.md
Installation
Docker (Recommended)
# From Docker Hub
docker pull neyslim/ultimate-ca-manager:2.185-rc1
# Or from GitHub Container Registry
docker pull ghcr.io/neyslim/ultimate-ca-manager:2.185-rc1
# Run
docker run -d -p 8443:8443 \
-e SECRET_KEY=$(openssl rand -hex 32) \
--name ucm neyslim/ultimate-ca-manager:2.185-rc1Debian/Ubuntu
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.185-rc1/ucm_2.185.rc1_all.deb
sudo dpkg -i ucm_2.185.rc1_all.deb
sudo apt-get install -fFedora/RHEL
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.185-rc1/ucm-2.185.rc1-1.fc43.noarch.rpm
sudo dnf install ./ucm-2.185.rc1-1.fc43.noarch.rpmSilent/Automated Install
# Skip firewall prompts for CI/automation
sudo UCM_PORT=8443 UCM_FIREWALL=no dpkg -i ucm_2.185.rc1_all.debDefault Credentials
- Username:
admin - Password:
changeme123
Change the password immediately after first login!
Documentation
- Installation Guide
- API Documentation