Release Notes¶
MazeVault Platform Version History
Document Version: 1.0.61 Last Updated: 2026-11-13
Version 1.0.61¶
Release Date: Unreleased
Distribution Changes (action required)¶
- Agent requires an
https://backend URL (check before upgrading agents) — An agent whoseserver_url(MAZEVAULT_SERVER_URL) useshttp://now stops at start with a configuration error unless the host islocalhostor a loopback address: tokens, private keys and secrets travel over this connection. Agents with a remotehttp://URL must be switched to thehttps://address of the backend or gateway before they can update: an agent of this version or later refuses a self-update while its own URL would fail this rule and reports the refusal to the backend (update_errorin its health status), but an agent older than this release still installs the update and then does not start, after which it can no longer be reached remotely. - API token scopes are enforced; CIDR-restricted roles apply (check scoped tokens before upgrading) — An API token (
mvt_…) created withscopesnow acts only within them on every permission-checked endpoint (before, scopes were checked for no token at all): a CI token with["secret:read"]can no longer write or delete, and a scoped token can create further tokens only within its own scopes. A token without scopes keeps all of its owner's rights; the web interface, the Go SDK and the Terraform provider create tokens without scopes unless you pass them. Before upgrading, check the scopes of tokens used by the CLI, SDK, Terraform provider or the Kubernetes operator:SELECT name, scopes FROM api_tokens WHERE is_active AND deleted_at IS NULL AND scopes IS NOT NULL AND scopes <> '{}';. The client IP now reaches the permission check, so roles with a CIDR restriction apply to clients inside the range (they never applied before) and anip_whitelistcondition on an environment permission is evaluated. Behind a reverse proxy, setTRUSTED_PROXY_CIDRSto the proxy addresses: only from them isX-Forwarded-Forused (the first address from the right that is not a trusted proxy); a request withX-Forwarded-FororX-Real-IPfrom any other peer gets no IP and CIDR-restricted roles do not apply to it. The same variable also enables theX-Client-Cert/ssl-client-certheader path of mTLS client certificates, so the proxy must strip those headers from client requests. A token created with an API token expires no later than that token, and a non-positivedurationis rejected with 400. An environment permission withmfa_requiredstill never applies, because sign-in tokens do not carry the MFA state yet; one withtime_rangeis re-evaluated on every request. - Permissions come only from role assignments (action required) — The role in a user's sign-in token (
users.role) no longer grants anything: a user has exactly the permissions of their role assignments (global, organization or project). Before, a user without any role assignment still got the permissions ofusers.roleeverywhere, and a user whose scoped assignment had been removed (or whose project or organization had been deleted) kept them until a re-sync. Users who had access only throughusers.rolelose it after the upgrade, and SSO and LDAP users created without a matching group mapping get no permissions until a role is mapped or assigned. Before upgrading, list the affected users withSELECT u.id, u.email, u.role FROM users u WHERE u.deleted_at IS NULL AND NOT EXISTS (SELECT 1 FROM user_roles ur WHERE ur.user_id = u.id);and give each one a role in Access Control → Manage roles (orPOST /api/v1/rbac/users/{id}/roleswithrole_idand an optionalscope). The built-in admin accounts get their admin assignment automatically at startup. Agents, OAuth clients and service identities are not affected. - Agent version policy replaces the agent version environment variables — Which agent version each agent is offered is now set by the version policy (Deployment → Agents → Version policy).
AGENT_VERSION,AGENT_MAX_ALLOWED_VERSIONandAGENT_ROLLOUT_PERCENTAGEare deprecated: they seed an empty policy once on the primary's first start (later changes to them only log a deprecation warning). Pinned values become targets and the ceiling, so agents running a higher version are offered a downgrade to them — clear the targets/ceiling in the policy or set a minimum rollback version if that is not wanted. Gateways follow the primary's policy. The new agent rollback floormin_rollback_versionlimits how far an agent may be rolled back; it can be cleared withreset-min-rollback-version. - Images, Helm chart and Compose kit move to the MazeVault Harbor — Starting with this release, MazeVault is distributed only from
registry.mazevault.com: imagesregistry.mazevault.com/mazevault/mazevault-{backend,frontend,docs,ocsp,init-certs}:vX.Y.Z, the Helm chartoci://registry.mazevault.com/mazevault/mazevault-customer(versionX.Y.Z), and the Compose kit (installer, upgrade/rollback scripts,docker-compose.yml,.env.example,SHA256SUMS) as OCI artifactregistry.mazevault.com/mazevault/compose-kit:vX.Y.Z, downloaded withoras pull(run its scripts withbash, ORAS does not keep the executable bit). Each customer receives a pull-only robot account; there is no GitHub token and noraw.githubusercontent.comdownload any more.v1.0.60and older remain on GHCR (ghcr.io/mazevault); existing installations keep theirIMAGE_REGISTRYuntil it is changed explicitly (install-mazevault.sh --registry, or the chart'simage.repositoryvalues). - The online installer uses the kit's
docker-compose.yml—install-mazevault.shno longer writes its own embedded copy of the compose file; it installs thedocker-compose.ymlshipped next to it in the Compose kit (asinstall-mazevault-offline.shalready did) and stops with an error when it is missing, so run it from the extracted kit. Online installations re-run with this release therefore pick up the kit's settings, e.g.MAZEVAULT_ENV_CANONICAL_ENFORCE(defaultfalse);MAZEVAULT_CUSTOMER_NAME,MAZEVAULT_CUSTOMER_EMAILandMAZEVAULT_COMPANY_IDmust be non-empty in.env(the installer always generated them). The kit's compose file gains the backend health check the installer's copy had, and the frontend starts once the backend is healthy. New switches for automation:MAZEVAULT_NO_SYSTEMD=1skips the systemd service and allsystemctlcalls, andMAZEVAULT_COMPOSE_PROJECToverrides the Compose project name (defaultmazevault). A newly generated systemd unit now passes the project name (-p) toupanddown; the unit is generated only when it does not exist, so an existing/etc/systemd/system/mazevault.servicekeeps its old command (delete it and re-run the installer to regenerate it). - Generated gateway stacks pull the backend from
MAZEVAULT_IMAGE_REGISTRY(default the MazeVault Harbor) at the primary's own version, and requireMAZEVAULT_GATEWAY_ENVIRONMENTwhen installed. - Customer Helm chart — External Secrets resources use
external-secrets.io/v1(External Secrets Operator 0.16 or newer is required); the backend runs plain HTTP behind the ingress (MAZEVAULT_TLS_ENABLED=false); the Redis access key is URL-encoded inREDIS_URL. The docs host moves to its own Ingress<release>-docs(same certificate), and the newglobal.ingress.docsAllowedSourceRangeslimits it to the listed client CIDRs. - Agent writes only inside allowed directories (check before upgrading agents) — The agent now writes files the backend names (
certificate_synckeystores,certificate_file_syncfiles,secret_synctargets,keytab_deploykeytabs, renewed certificates, file and JKS targets of the periodic sync) only insidecert_store_pathand the new agent settingallowed_write_paths. Without the setting the defaults are/etc/ssl,/etc/pki,/etc/letsencrypt,/etc/nginx/ssl,/etc/nginx/certs,/etc/apache2/ssl,/etc/httpd/ssl,/etc/haproxy/certs,/etc/krb5.keytab,/var/lib/mazevault/certsand/etc/mazevault/certson Linux,C:\ProgramData\MazeVault\certson Windows. Paths must be absolute (a relativesecret_synctarget_pathis now refused) and must not contain..; symlinks are resolved before the check; the agent's own configuration, identity and state are never writable this way. Before upgrading an agent, add toallowed_write_pathsin itsagent.yamlevery other directory its deployment targets, secret sync targets, keytab targets or renewed certificates use (for example/opt/tomcat/conforC:\inetpub\app); a refused path fails the request with an error namingallowed_write_paths, except for the periodic certificate sync (file and JKS targets,install_targetmetadata), whose refusals appear only in the agent log (/var/log/mazevault/agent.logor the journal,C:\ProgramData\MazeVault\logs\agent.logon Windows) — search it forallowed_write_pathsafter the upgrade. A relativecert_store_pathorallowed_write_pathsentry now stops the agent at start with a configuration error. On Windows, junctions and mount points inside a write path are refused.keytab_renewignoresoutput_pathand always generates the keytab into a private temporary file. A renewaloperation_tokenis now accepted only as a plain name (letters, digits,-,_), and the certificate id the agent fetches after an enrollment is sent path-escaped. See Agent Deployment → Allowed write directories. - Agent deployment API —
os_type: darwinandagent_mode: gateway|sidecarare rejected with HTTP 400; supported agents are Linux and Windows hosts. - Certificate authorities: the legacy external-CA configuration endpoints are removed —
POST /api/v1/ca/{id}/external/configure,POST /api/v1/ca/{id}/external/test,POST /api/v1/ca/{id}/external/templates/syncandPOST /api/v1/projects/{id}/ca/{caId}/external/configureno longer exist (a call now returns HTTP 404); external CAs are configured as organization CA accounts. Migration000217drops theexternal_ca_configsandexternal_ca_template_mappingstables, keeping any rows inmazevault_internalfor its down migration. - Azure Key Vault integrations: the Default Credential Chain auth method is removed (check before upgrading) — The Auth Method step of an Azure Key Vault integration offers On-Behalf-Of, Managed Identity and Client Secret (interactive) and Client Secret and Managed Identity (background). The API, and so the Terraform resource
mazevault_integration, answers400fordefaultininteractive_auth_method,background_auth_methodorconfig.auth_methodon create, update and connection test. Migration000211setsclient_secretin place ofdefaulton existing Azure Key Vault integrations and disables them with the last sync errorDisabled by migration 000211: the Default Credential Chain auth method was replaced by Client Secret; choose Managed Identity or Client Secret and enable the integration; edit each one, choose Managed Identity or Client Secret (with the app registration's tenant ID, client ID and secret) and enable it again. List them before upgrading withSELECT id, project_id, environment, name FROM project_integrations WHERE provider IN ('azure', 'azure_keyvault', 'azure_key_vault') AND (interactive_auth_method = 'default' OR background_auth_method = 'default');. Its down migration restores the previous values frommazevault_internal.migration_000211_default_auth_method_backup. An Azure auth method the server does not know (for example a typo inconfig.auth_method) fails withunsupported Azure auth method, and an integration with no auth method and no client credentials fails withno Azure auth method configured; the server's own Azure identity is not used in their place. Rotation preflight now also blocks a rotation whose Key Vault propagation target or post-rotation Key Vault action points to a disabled integration. See Azure Identity & Permissions Configuration, section 9.2. - SSO: the OIDC / OAuth2 provider type is removed — Organization Settings → SSO no longer offers OIDC / OAuth2; it had no sign-in behind it. The API, and so the Terraform resource
mazevault_identity_provider, accepts onlyentra_idandldapastypeon create and answers400for any other value,oidcincluded; the Terraform resource also refuses anothertypeatterraform plan. Migration000212deletes existingoidcidentity providers the way the API does (soft delete); its down migration restores them frommazevault_internal.migration_000212_oidc_identity_provider_backup. Sign in through Microsoft Entra ID (which uses OpenID Connect) or LDAP. - SSO: SAML 2.0 sign-in is removed — Organization Settings → SSO no longer offers SAML 2.0, and the endpoints
GET /api/v1/auth/saml/metadata,GET /api/v1/auth/saml/loginandPOST /api/v1/auth/saml/callbackno longer exist. The API, and so the Terraform resourcemazevault_identity_provider, answers400fortype: samlon create. Migration000213deletes existingsamlidentity providers the way the API does (soft delete); its down migration restores them frommazevault_internal.migration_000213_saml_identity_provider_backup. Users who signed in through SAML keep their accounts and sign in through Microsoft Entra ID or LDAP with the same email address. - SSO: GitHub sign-in is removed — The endpoints
GET /api/v1/auth/sso/github/loginandGET /api/v1/auth/sso/github/callbackno longer exist, Organization Settings → SSO no longer offers GitHub, and the backend no longer readsGITHUB_CLIENT_ID,GITHUB_CLIENT_SECRETandGITHUB_REDIRECT_URI; remove them from your environment or secret store. The API, and so the Terraform resourcemazevault_identity_provider, answers400fortype: githubon create. Migration000214deletes existinggithubidentity providers the way the API does (soft delete), moves the users' GitHub identities into a backup and deletes pending GitHub sign-in states; its down migration restores the providers and identities frommazevault_internal. Users who signed in through GitHub keep their accounts and sign in through Microsoft Entra ID or LDAP with the same email address. GitHub secret sync integrations are not affected. - SSO: GitLab sign-in is removed — The endpoints
GET /api/v1/auth/sso/gitlab/loginandGET /api/v1/auth/sso/gitlab/callbackno longer exist, Organization Settings → SSO no longer offers GitLab, and the backend no longer readsGITLAB_CLIENT_ID,GITLAB_CLIENT_SECRET,GITLAB_REDIRECT_URIandGITLAB_BASE_URL; remove them from your environment or secret store. The API, and so the Terraform resourcemazevault_identity_provider, answers400fortype: gitlabon create; SSO is configured withentra_idorldap. Migration000215deletes existinggitlabidentity providers the way the API does (soft delete), moves the users' GitLab identities into a backup, deletes pending GitLab sign-in states and drops the unused columnsgithub_org,github_team_restrictionsandgitlab_group_restrictionsofidentity_providersafter copying their values into a backup; its down migration restores all of it frommazevault_internal. Migration000216then drops the tableauth_identities, which held only the GitHub and GitLab sign-in links, after copying any remaining rows intomazevault_internal. Users who signed in through GitLab keep their accounts and sign in through Microsoft Entra ID or LDAP with the same email address. GitLab secret sync integrations are not affected. - Secret import endpoint removed —
POST /api/v1/projects/{id}/secrets/importhas been removed together with the preview External Migrations tab in Organization Settings. Secrets are created withPOST /api/v1/secretsand updated withPUT /api/v1/secrets/{id}; export (GET /api/v1/projects/{id}/secrets/export) is unchanged. - SCEP enrolment requires a challenge password (security fix, check before upgrading) —
PKIOperationenrolment at/api/v1/scep/<ca_id>used to sign every CSR with the internal CA without checking anything, so anyone who could reach the endpoint obtained a client certificate of your CA. It is now authorised by the CSR'schallengePassword, which must match the new backend variableSCEP_CHALLENGE_PASSWORD(one value for all internal CAs; in Helmglobal.keyVault.secretKeys.scepChallengePassword). The variable is not set after an upgrade, so every SCEP enrolment is refused (signedCertRepFAILURE/badRequest, no certificate; the backend logsSCEP enrolment disabledat start and a warning per refused request). If you use SCEP (e.g. Intune, Jamf, sscep), setSCEP_CHALLENGE_PASSWORDto a strong random value and configure the same challenge in the SCEP clients/profiles;GetCACapsandGetCACertare unchanged. Setting the variable enables SCEP for every organization's internal CA, and anyone holding the value can enrol at any of them: in a multi-organization deployment set it only if all organizations trust each other, otherwise leave SCEP off. Certificates issued through SCEP earlier stay valid; review them and revoke any you do not recognise. - Terraform: changes the API cannot apply now plan a replacement or fail the plan (review
terraform planbefore applying) — Several Terraform attributes could be changed in place although the backend cannot change them: the apply either failed ("Provider produced inconsistent result", "Update not supported") or reported success and silently dropped the change. They now force replacement (destroy and create):mazevault_secret.project_id,keyandenvironment;mazevault_api_token.name,scopesandduration;mazevault_shared_secret.ttl_hoursandmax_views;mazevault_group_mapping.group_nameandrole_id; every argument ofmazevault_secret_link;project_idofmazevault_integration,mazevault_integration_groupandmazevault_consistency_group;mazevault_hsm_device.provider_type. A replacement also replaces every resource that references the replaced one (for example the secret links of a replaced integration). Replacing a secret deletes its version history and writes the value from the configuration again: a secret withgenerategets a new random value, and a value rotated on the server reverts to the configured one. Replacing an API token revokes the old token and issues a new value (considerlifecycle { create_before_destroy = true }), and a replaced share link is not revoked (shares cannot be deleted): it stays valid until it expires or is claimed, next to the new one. Two changes now fail at plan time instead, because a replacement would be destructive or cannot succeed:mazevault_project.organization_id(the API cannot move a project; a replacement would delete the project with every secret in it: create a new project and migrate instead), anddisplay_name,descriptionandpermissionsofmazevault_rolewhilenamestays (the API can neither change nor delete a role: change it in MazeVault, or give it a newname, which creates a new role). A role withoutdescriptionno longer shows a change after a refresh (also when an older provider version stored it as ""), a change of only the letter case of aproject_idorrole_iddoes not replace anything, a role adopted after "role already exists" must match the configuration, androle_id,organization_idandproject_idread back in another letter case no longer show a change.mazevault_group_mappingnow stores the planned values on update instead of the previous state. Keepenvironmentofmazevault_secretnon-empty: the backend stores an empty one asdev, and the next plan would replace the secret. - Certificates are always created in a project (API callers: check before upgrading) — Every API path that creates or imports a certificate now needs a project:
POST /api/v1/certificates/import,/import/bulkand/import/file(including PFX) and a user'sPOST /api/v1/certificates/csranswer HTTP 400project_id is requiredwithoutproject_id(the UI always sent one; adopting a discovered certificate andPOST /api/v1/projects/{id}/csralready required it). Sendproject_id; in Terraform setproject_idonmazevault_certificate, in the CLI passmazevault certs request --project <id>(the flag replaces the required--agent). Agent mTLS enrolment, the agent's Kubernetes controller and gateway mTLS certificates are not affected. Certificates without a project left from older imports belong to no organization: only a global role sees and manages them, an organization or project role gets 403, and an import of the same certificate into a project is refused instead of taking it over. A global admin assigns such a certificate to a project withPUT /api/v1/certificates/{id}(project_id); from then on the project's organization manages it. - Multi-datacenter sync: the event payload format changes (upgrade every datacenter together) — Sync events between datacenters (
POST /api/v1/sync/events,GET /api/v1/sync/events,GET /api/v1/sync/entities/{id}) now carry the entity data, including a secret's encrypted value, and acknowledgements (POST /api/v1/sync/ack) are stored. Before, events carried no data and every acknowledgement failed, so no secret, certificate or other entity was replicated and the same events were sent again forever. A replicated entity keeps its id on every datacenter, and a replicated update no longer clears a user's password hash or other fields the event does not carry. Run the same release on the primary and every gateway: a datacenter of an older release can neither send nor apply the new events. After the upgrade the primary sends the events it stored earlier as well (a datacenter skips events it has already received); a secret event stored before the upgrade lacks the value, so a secret missing on the receiving datacenter is not created from it and replicates with its next change. On an installation that synced before, each gateway has already stored the first batch (up to 100 events) without data and skips it now, so users, roles, organizations, projects and certificates in that batch do not replicate until they change: after upgrading every datacenter, save these entities again on the primary (a reconciliation does not help, both sides hold the same event checksums). A secret that reconciliation fetches from a primary of an older release, without its value, is stored asnames_only. All datacenters must use the same encryption key (MAZEVAULT_MASTER_KEY), as before. API responses never contain the encrypted value, and the sync dashboard (/api/v1/sync-dashboard/events) lists events without their data. The Redis secret cache now holds the encrypted value of cached secrets (ciphertext underMAZEVAULT_MASTER_KEY, never the plaintext). - Go SDK: set
EnabledandSyncOnSuccesswhen creating a rotation target (action required) —POST /secrets/{id}/rotation/targetstreats an omittedenabledorsync_on_successastrue, but the Go SDK request struct sends plain booleans withoutomitempty, so a caller that leaves them unset sendsfalseand gets a disabled target that never syncs (before, the database default turned thatfalseintotrue). Set both fields explicitly (Enabled: true, SyncOnSuccess: true) in code that creates rotation targets through the SDK. - OCSP responder:
X-Forwarded-Foris trusted only fromTRUSTED_PROXIES; request limits (check the rate limit behind a proxy) — The OCSP responder's per-IP rate limit (RATE_LIMIT_ENABLED,RATE_LIMIT_BY_IP) no longer believes the client-suppliedX-Forwarded-Forheader, which let a client bypass the limit with a different value per request: the limit keys on the peer address unless the peer is listed in the newTRUSTED_PROXIES(comma-separated IPs or CIDRs; Helmocsp.config.TRUSTED_PROXIES, Compose kitOCSP_TRUSTED_PROXIES), and then on the first address from the right of the header that is not a trusted proxy. Behind a reverse proxy or load balancer setTRUSTED_PROXIESto its addresses, otherwise all clients share the proxy's bucket. A POST body larger than 64 KiB is refused with413, a POSTContent-Typewith parameters (application/ocsp-request; charset=binary) is accepted, andGET /answers400 Missing OCSP request. - OCSP responder: shorter response cache (
CACHE_TTLdefault 1 minute) and CA registry refresh — The responder shows a revocation after at mostCACHE_TTL, because the responder runs separately and is not told about revocations: the default (and the value in the Helm chart and Compose files) drops from 10 minutes to 1 minute; setCACHE_TTLhigher only if a longer window is acceptable. Clients may still keep an earliergoodanswer until itsnextUpdate(RESPONSE_VALIDITY, 1 hour by default). The responder now reloads its certificate authorities everyCA_REFRESH_INTERVAL(default 5 minutes,0disables), so a new or renewed CA is served without a restart, and a failed reload keeps the previous CAs. An unsignedunauthorizedanswer (unknown CA) is no longer cached forever. - OCSP responder: key check, nonce echo and HSM report — The responder refuses to sign (answers
internalErrorand logs the error) when a CA's private key does not match its certificate, instead of serving a response with an invalid signature. A request with a nonce extension (RFC 8954) gets the same nonce in the response (such responses are not cached); a nonce longer than 32 octets is answered withmalformedRequest. Certificate authorities withhsm_enabledare reported when they are loaded (log lineOCSP: CA … is unavailableand the gaugeocsp_unavailable_cas) while no HSM signer is configured; no HSM provider is implemented yet, so such a CA still answersinternalError. - Go SDK and Terraform: deployments carry their organization, new import IDs, whole-day rotation workflows (action required for SDK callers and imports) — The backend takes the organization of an agent deployment from the create body and from
?organization_id=on list, but the Go SDK sent neither, so creating a deployment failed with 403 and reading one with 400;mazevault_deploymentcould neither create nor refresh a deployment. Breaking Go SDK changes:CreateDeploymentRequesthas a newOrganizationIDfield (set it), andListDeployments(organizationID)andGetDeployment(id, organizationID)take the organization.CreateRotationWorkflowRequesthas a newEnvironmentfield:CreateRotationWorkflowstores it with an update right after the create (the create endpoint does not take it), andRotationWorkflowDetail.Resource.EnvironmentScopereturns it. Terraform:mazevault_rotation_workflow.environmentis now sent and read back (it was never sent, so every refresh showed a change), andttl_hoursmust be a positive multiple of 24, because the backend stores whole days (24 h → 1 day). Before,ttl_hours = 36was stored as 1 day without notice; such a configuration now fails at plan time, so change it to a multiple of 24. Import IDs:mazevault_deploymentis imported as<organization_id>/<deployment_id>andmazevault_certificate_templateas<project_id>/<template_id>; the plain ID used before is refused. After an import,mazevault_carestoresnameandvalid_years,mazevault_certificate_templaterestorestypeandvalidity_period(as<n>d),mazevault_integrationrestoresproject_idandenvironment, andmazevault_rotation_workflowrestoresenvironmentandttl_hours, so the next plan no longer replaces the imported object. - SSO: SCIM provisioning is removed — Organization Settings no longer offers SCIM provisioning, and its tab SSO & Provisioning is now called SSO. The SCIM 2.0 endpoints under
/api/v1/auth/scim/{providerID}/(Users,GroupsandServiceProviderConfig) no longer exist, so an identity provider that still pushes to them gets404; remove the SCIM provisioning from your Microsoft Entra ID or Okta application. Migration000299drops the tablesexternal_identitiesandexternal_group_memberships, which held the users and groups pushed through SCIM, and removes the SCIM token hash (scim_token_hash) from the identity providers' configuration; the identity provider remains the source of this data, and the down migration recreates only empty tables and columns. Users created through SCIM keep their accounts; they sign in through Microsoft Entra ID when their stored external ID is their Entra object ID or when they have signed in through Entra SSO before, otherwise they need the one-time re-link described under Entra ID SSO: Nonce Always Enforced, No More Linking by E-mail. The same migration drops the columnsusers.deactivated_atandusers.scim_provider_idthat migration000223of this release adds; on an installation that ran a pre-release build with SCIM deprovisioning, users that SCIM had deactivated are moved to the Archive and their API tokens are switched off. - Login page: the Google button is removed — The login page no longer shows a Google button; it had no sign-in behind it (the endpoint did not exist).
googleis no longer listed as a userprovidervalue in the API schema. Sign in with a local account, LDAP or Microsoft Entra ID.
Removals (action required)¶
- Rotation: scripts and direct agent URLs no longer run from the MazeVault server (check before upgrading) — A
shell_scriptpost-rotation action now runs only on a gateway: setgateway_idon the action (API or Terraform). Without it the MazeVault server refuses the action (shell_script runs only on a gateway) instead of running the script on its own host with its own environment; this includesrollback_script. Certificate post-rotation actions are not delegated to gateways, so a certificateshell_scriptaction always fails now: replace it with anagent_commandon a registered agent. The directagent_urltarget ofagent_secret_sync,agent_commandandiis_recycleis removed: no MazeVault agent served those calls and they were sent unauthenticated, so the server now refuses such an action (direct agent_url targets are no longer supported) before sending anything, also when an integration's configuration only carriesagent_url/gateway_urland no agent. Useagent_idof a registered agent (or an integration bound to an agent). Rotation preflight blocks a post-rotation action with a directagent_url(agent_url_unsupported), the Entra rotation settings refuse to save one, and the certificate rotation tab no longer offers Direct Agent URL. Existing configurations are not changed; find the affected ones withSELECT 'secret' AS kind, id FROM rotation_configs WHERE post_rotation_actions::text LIKE '%agent_url%' OR post_rotation_actions::text LIKE '%shell_script%' UNION ALL SELECT 'certificate', id FROM certificate_rotation_configs WHERE post_rotation_actions::text LIKE '%agent_url%' OR post_rotation_actions::text LIKE '%shell_script%' UNION ALL SELECT 'template', id FROM rotation_config_templates WHERE post_rotation_actions::text LIKE '%agent_url%' OR post_rotation_actions::text LIKE '%shell_script%' UNION ALL SELECT 'entra_credential', id FROM entra_credentials WHERE extended_rotation_config LIKE '%agent_url%';and update them before the next rotation. Gateway access is not yet restricted per organization: anyone allowed to edit a rotation's post-rotation actions can name any gateway, so limit who holdssecret:rotateuntil that is fixed. - SSH Management Removed — The Enterprise Functions → SSH Management page and everything that served only it are removed: SSH key pairs, authorized-key deployment and revocation, SSH key discovery, the SSH CA and SSH rotation configs, the SSH Keys tab in Access Control, the SSH section in Reports, and SSH rows and links in rotation views. The
/api/v1/ssh/*and/api/v1/users/{id}/ssh-keysendpoints, the agent endpoints/agents/me/ssh-discoveryand/agents/me/authorized-keys/*, thessh_key_pairrotation resource kind, thessh_managementlicense feature, thessh:*permissions and the built-inssh_adminrole are gone. The Terraform provider no longer listsssh_key_pair/ssh_keyas rotation resource kinds. Export any SSH private keys you still need before upgrading: migration000218_remove_ssh_managementdeletes all SSH key pairs (including their encrypted private keys), authorized-key deployments, discovered keys, issued SSH certificates, SSH rotation configs and thessh_key_pairrotation history and approvals, and stripsssh:*from roles, environment permissions, API tokens and OAuth clients. The down migration recreates only empty tables. - SSH CA Key Retired and Its Private Key Wiped — Migration
000218retires every version of the SSH CA system key (ssh_ca) and deletes its private key; the key stays visible as retired under System Keys, and Rotate on it is refused. The private key then exists only in database backups taken before the upgrade. Already-signed SSH certificates stay valid until they expire. RemoveTrustedUserCAKeys /etc/ssh/mazevault_ca.pub(or your equivalent) fromsshd_configon your servers. - Keys Already Deployed to Servers Stay There — MazeVault no longer deploys or revokes
authorized_keysentries. Keys it deployed earlier, including any still waiting for revocation, are not removed from servers; clean them up manually. Upgrade agents as well: older agents keep working but log a 404 for their SSH discovery and authorized-key calls on every discovery cycle. - What Stays — Projects of type
ssh, the SSH certificate type of CA providers (e.g. Smallstep), storing SSH keys as ordinary secrets or keys, audit logs and key custody events about SSH keys. Existing HSM devices with thessh_keysscope keep it, but the scope is no longer offered for new devices. - Governance Import Removed — The Governance Import tab in Organization Settings → System Outputs is removed, together with the upload of audit-tool reports, their parsed policy requirements, the drift analysis against them and the drift trend. The
/api/v1/governance/*endpoints (reports, analyze, drift, drift trend and the report JSON schema) return 404. Migration000220drops thegovernance_reportsandgovernance_drift_snapshotstables, so uploaded reports and drift history are deleted; they exist afterwards only in database backups taken before the upgrade. The other System Outputs tabs are unchanged. - Unused certificate sync-config stub endpoints removed —
GET/PUT /api/v1/organizations/{id}/sync-config,GET/PUT /api/v1/projects/{id}/sync-configandPOST /api/v1/projects/{id}/sync-config/set-masterare removed and answer404. They answered success but never stored or returned anything, and neither the web interface, the SDKs, the CLI nor the Terraform provider called them; project sync settings stay at/api/v1/projects/{id}/sync-settings.
New Features¶
- Agent packages (
.deb,.rpm,.msi) — The agent can be installed with your own tooling from signed system packages:.deband.rpmfor Linux amd64 and arm64,.msifor Windows x64. Download them under Deployment → Deploy → Install from packages or withGET /api/v1/agent-packages(permissiondeployment:read); enroll withmazevault-agent enrollor the MSI propertiesSERVER_URLandBOOTSTRAP_TOKEN. After installation the agent keeps updating itself by the version policy. The MSI is not Authenticode-signed yet. The backend image bundles the packages of its own agent version; other versions come from the MazeVault Harbor (agents/agent-packages). See Agent Deployment → Installing from Packages. - Deployment token lifetime and use limit — A deployment can set how long its bootstrap token is valid (
expires_in_days: 1–3650,0= never; default 30 days as before) and how many agents may register with it (max_uses,0= unlimited), in the UI, the API and the Terraform resourcemazevault_deployment. The UI warns about a token without expiry or use limit. - systemd unit of the agent — The unit written by the install script and shipped in the packages now starts the agent only when
/etc/mazevault/agent.yamlor the pre-seed file/etc/mazevault/enroll.confexists. - Roles for Service Identities — A service identity can now be given roles:
POST /api/v1/service-identities/{id}/roles,GETon the same path andDELETE /api/v1/service-identities/{id}/roles/{assignmentId}(permissionsrole:assign/role:readon the identity), the new Roles dialog on the Service Identities page, the Go SDK (AssignServiceIdentityRole,GetServiceIdentityRoles,RemoveServiceIdentityRole) and the Terraform resourcemazevault_service_identity_role. The role applies in the identity's organization or in one of its projects only; a global scope or a scope in another organization is rejected with 400, and an identity without an organization gets no roles. As for users, you can assign or remove only a role whose permissions you hold yourself in that scope (else 403). A removal applies to the identity's next request. A role that happens to be namedserviceno longer applies to every service identity through the token's role claim: an identity has only the roles assigned to it. Migration000250addsorganization_idtoservice_identity_roles; rows written there outside the API before the upgrade are confined to the identity's organization: a row without a project gets the identity's organization, a row of an identity without an organization or whose project or organization belongs to another organization is deleted, and each kept or deleted row is listed as a warning in the PostgreSQL log. The permission engine also ignores any identity role row outside the identity's organization. - Terraform Provider: Onboarding a Fresh Installation — The provider now covers the organization setup that previously required the UI.
mazevault_config_templatefollows the Configuration Management contract (template_type+ JSONdefinition, validated by the backend at plan time; the formercontent/formatarguments never worked against the API). Newmazevault_project_templatemanagessecrets/keysProject Templates,mazevault_entra_integration_scopeselects the Entra ID applications a project integration manages (with Graph sync after apply), and the data sourcemazevault_entra_app_registrationresolves the credential IDs formazevault_entra_rotation_config.mazevault_ca_accountgains a write-onlycredentialsmap for self-hosted CAs (Smallstep, ADCS, Vault, EST) and rejects secret-looking keys in the plaintextsettings.mazevault_certificategainskey_storage_mode,key_integration_idandkey_secret_nameso server-side generated private keys can be offloaded to a secret manager (required in Orchestrator Mode). See Terraform Provider Guide → Onboarding a Fresh Installation. - Effective Certificate Chain: Intermediate CAs Export With Their Root — Exporting an intermediate CA (or any certificate) that was imported without its issuer chain now includes the issuing CA and root automatically whenever the issuer is present in the organization inventory. A new
CertificateChainResolveris the single source of truth for the effective chain: a chain captured on the record at import or issuance is returned byte-for-byte and never extended; only certificates with no stored chain are completed from CA certificates managed in the same organization (including the internal CA and the record's explicit CA link), and a candidate is accepted solely when it cryptographically verifies the certificate's signature — a matching Distinguished Name alone never links two certificates. Roots are included, archived candidates are ignored, a revoked issuer is used only when nothing else verifies and is reported as a warning, and issuers signed with insecure algorithms are rejected with a warning. The same chain is used by the export API (include_chain=true, all formats), by the certificate detail (Chaintab now shows the provenance — Stored with certificate / Resolved from inventory / No chain — plus completeness to the root and warnings), by the agent certificate list, and by the Terraform data source, so every consumer sees identical material. Reading never writes to the database; the chain is persisted only when an import or adoption writes a certificate body that has no chain. TheGET /certificates/{id}response gainschain_source,chain_completeandchain_warnings; themazevault_certificatedata source gainschain_pem,chain_sourceandchain_complete, and itscertificate_pemattribute — previously mapped to a field the API never returned — is now populated frompublic_chain_pem. New Prometheus metric:mazevault_certificate_chain_resolution_total{source,complete}. - Discovered Certificates Keep Their Body; Adoption Yields a Deployable Certificate — Agent discovery now persists the public leaf certificate and the issuer chain it observed (migration
000199, columnscertificate_pem/chain_pemondiscovered_certificates; public material only, never a key). Adopting a discovered certificate therefore produces a managed certificate with a body that can be exported, deployed and verified; managed certificates adopted before this release receive their body automatically on the next agent scan through the existing thumbprint auto-link, and a reported chain is stored as-is (completed from the inventory only when the agent reported none). The discovered-certificate detail (GET /discovered-certificates/{id}) returnscertificate_pem,chain_pemandchain_certificates; list responses deliberately omit the body so the Discovered Certificates page stays fast. Identity (serial, thumbprints) is now derived from the certificate DER instead of being trusted from the agent report. - Certificate Body From CA Synchronisation and From Manual Import — The body is now also kept for certificates synchronised from a CA listing (HashiCorp Vault, DigiCert, ADCS, SSLMarket and the local-inventory providers used for ACME / I.CA / PostSignum):
ParseCertificateMetadatacarries the normalized PEM into the discovered record, a re-run of the CA synchronisation back-fills discovered records that were created without it, and a managed certificate linked by thumbprint that has no body receives it the same way the agent path does. In addition, importing the public certificate alone (CRT/PEM/DER, or a PFX) now completes a managed certificate that has no body instead of being rejected as "already exists": the import is matched by thumbprint (or pinned withexpected_certificate_idfrom the certificate detail), the body is stored together with the identity and descriptive columns derived from it (canonical serial, thumbprints, subject/issuer, validity, key and signature algorithms, key usage, SAN set, certificate type; anactivestatus is refreshed, a revoked or pending one is never changed), and a chain-less record is completed from the inventory. Private key handling on such a record follows the approved rule: a key supplied together with the certificate is attached when the record has no custody; a key that matches an existing custody is an idempotent re-import; a key that does not match is rejected with an explicit error after the body was stored — the record is never left without a body because of a wrong key. A locally stored key that could not be verified at the time it was imported (the record had no body) is verified when the body arrives and, if it does not belong to the certificate, is flagged (metadata.private_key_mismatch, audit eventcertificate.private_key_mismatch) but never deleted. Bulk/file import items reportmessage: "existing certificate record completed with the uploaded certificate body"for this case; the certificate detail shows a Complete certificate action for records without a body, and the discovered-certificate detail explains the manual path. One shared implementation (applyCertificateBodyToManaged) now backs discovery ingest, CA synchronisation, adoption and import, so every path yields the same fully described record (the previous re-scan path set key usage only in memory and did not persist it). - Agent File Deployment and Allowlisted Commands — Certificate rotation can now deploy to files on an agent host (
Agent File (PEM)target, stepagent_file_sync): the agent writes leaf, chain, key and an optional combined bundle (PEM or PKCS#12) according to the target's content mode (public_only,public_chain,full_chain_with_key,key_only), applies permissions and ownership, keeps the previous files as.BAK, installs the chain into the platform trust store when enabled, and runs the optional post-install command. Rotation steps that need a command on the host (service restart, WLST restart script, Oracleorapki) now execute through the new agentagent_commandrequest, which runs only commands matching the agent's built-in allowlist or an operator-configuredallowed_commandsregular expression. Oracle database wallet targets are now deployed for real: a one-time-password PKCS#12 is staged under<wallet>/mazevault/, imported withorapki wallet import_pkcs12(auto-login or password-protected wallets viawallet_password_ref), and always removed afterwards; the wallet and PKCS#12 passwords are flagged as sensitive so the agent redacts them in its audit log, its response and any rejection error, and the staging step carries no idempotency key so a retried rotation re-stages the file instead of replaying a stale result.update_tns_namesandrac_nodesare refused explicitly rather than ignored. WebLogic targets now deploy through a realweblogic_deploystep: the leaf and key are installed into the custom identity keystore (JKS or PKCS#12, backup viabackup_enabled), the issuer chain is optionally imported into the custom trust keystore (trust_store_path+ newtrust_store_type/trust_store_password_ref; each issuer is staged as its own PEM under<trust-store-dir>/mazevault/, imported withkeytool -importcert -trustcacerts, an alias that already exists counts as success and the staged file is always removed), and the managed server or cluster is optionally restarted through the operator'swlst_script_path(restart_modegraceful / force / rolling). The trust-store password is flagged as sensitive so the agent redacts it everywhere, and admin credentials are never placed on a command line — the WLST script must use stored credentials;admin_url,server_nameandcluster_nameare rejected when they contain shell metacharacters, and a restart mode requiresadmin_url. Structuredagent_commandrequests (keytool, orapki, WLST script) are executed by the agent directly with their argument vector, without a shell, so a password containing shell metacharacters can neither be reinterpreted nor echoed back by the shell; sensitive values are additionally scrubbed from the command output and error text before they leave the agent. Operator-authored post-install command strings keep their shell semantics. - Deployment Targets Are Validated When Saved — Creating or updating a certificate deployment target now validates it against what the system can actually execute, and returns
400with the reason instead of accepting a configuration that would later fail or be skipped: agent-based targets (agent_keystore,agent_file,database,weblogic) require an agent; a database wallet target requireswallet_path, an Oracle provider (SQL Server, PostgreSQL, MySQL and MongoDB have no wallet — the error names the Agent Keystore / Agent File target to use instead) andupdate_tns_names=false; a WebLogic target requireskeystore_path, a password reference for its trust store and a WLST script for any restart mode;web_serverandload_balancertargets are refused with the supported alternative because no deployment mechanism exists for them yet. The workflow builder applies the same validation, so an enabled target that cannot execute fails the rotation with the target ID and reason instead of being skipped silently. Disabling or re-prioritising an existing target with an invalid legacy configuration is always allowed, so operators can take it out of the rotation; enabling it again requires fixing the configuration. The rotation target editor in the UI mirrors these rules: Database Wallet requires an agent and is labelled Oracle, the non-Oracle providers and the Update TNS Names switch are disabled with the guidance text, Web Server is shown as not available yet and Load Balancer is hidden from the picker for new targets (an existing one still opens in edit mode with the explanation, so it can be disabled or deleted — nothing was removed from the API or the code), the backend's validation reason is shown when a save is refused, and the target list gained an Enable / Disable action that changes only theenabledflag — the way to take a legacy target out of the rotation without deleting it. - Secret Rotation Backups: Retention, Cleanup, and Manual Recovery — Every secret rotation captures an encrypted pre-rotation backup and now tracks it through an explicit lifecycle (
pending→released/restored/recovery_required→acknowledged). A daily cleanup job purges only terminal-state backups past their retention window, while backups whose automatic rollback failed are flaggedrecovery_requiredand are never auto-deleted. Operators can list backups, restore or reveal a pre-rotation value, and acknowledge a handled backup through newrotationAPI endpoints:GET /rotation/backups,POST /rotation/backups/{id}/restore,POST /rotation/backups/{id}/reveal, andPOST /rotation/backups/{id}/acknowledge. Reveal and restore additionally enforcesecret:readon the secret's environment inside the handler, and for externally-governed (orchestrator-mode /names_only) secrets no local value is ever stored or returned — the operator is directed to retrieve the value from the external provider under their own identity, so the API cannot become a side-channel around Key Vault access control. Retention is configurable via the newMAZEVAULT_ROTATION_BACKUP_RETENTION_DAYSvariable (default 7). Two Prometheus metrics were added:mazevault_rotation_backups_purged_totalandmazevault_rotation_backups_recovery_required. - Rotation Preflight Now Verifies Gateway and Agent Readiness Before Execution — The rotation preflight engine and orchestrator now evaluate the live readiness of every required execution target — gateways and post-action agents — before a rotation is allowed to start, instead of only checking configuration. A new
ProbeGatewayByIDmethod probes a specific gateway by ID, and a non-mutatingEvaluateReadinesspath assesses whether a rotation resource is ready without changing any state. The preflight engine distinguishes required from optional post-action agents, so a rotation that depends on an offline gateway or an unavailable required agent is classified and reported up front (feeding theready/deferred/blocked/manual-review-requiredoutcomes) rather than failing partway through. The rotation scheduler classifies gate errors more efficiently as part of this work. - Service Identity Grace-Period Revoker — A new background job hard-revokes client (service identity) secrets whose grace-period deadline has been reached, completing the "soft revocation" path that
RotateClientSecretstarts when a grace period is configured. Previously a rotated secret with a grace window relied on the old credential remaining valid, but nothing durably retired it once the window elapsed. The revoker runs periodically from the scheduler (default once per minute), materializes expired grace periods, and writes an audit record for each hard revocation. - Agent Lifecycle Management and Deployment Record Handling — Registered agents can now be managed through their full control-plane lifecycle from Deployment → Agents, and agent authentication is lifecycle-aware end to end. A new
RequireActiveAgentroute guard re-checks the agent's current status in the database on every JWT-authenticated agent request, so an agent that was unregistered, revoked, or deleted can no longer keep calling agent routes with an unexpired token; registration and the legacy hostname-discovery path no longer reactivate an inactive or revoked agent, and runtime consumers (rotation sync-target resolution, SSH key deploy/revoke, keytab rotation) refuse to route work through a non-active agent. Four newagent:adminendpoints back the console:GET /api/v1/agents/:id/lifecycle-impactreturns an advisory dependency summary (managed certificates, project bindings, rotation targets, SSH keys, pending keytab work, discovery/config/token references) with best-effort warnings;POST /api/v1/agents/:id/unregisterretires an agent — invalidating its mTLS identity and recovery tokens, deactivating project bindings, and stranding pending keytab work — or escalates to a security revoke when the reason category iscompromised/lost_credential/stolen_host, requiringforcepast unresolved blockers;POST /api/v1/agents/:id/reregisterretires the old identity and issues a single-use 24-hour replacement bootstrap token; andPOST /api/v1/agents/:id/uninstallasks a connected, capable agent to uninstall itself. Remote uninstall is capability-negotiated at request time and supported for Linux packaged (systemd) installs running as root and Windows MSI service installs: the agent accepts first, then a detached copy of the agent binary (escaping the service cgroup viasystemd-runon Linux, aDETACHED_PROCESSon Windows) performs the removal and reports the real outcome back over the health channel before self-destructing — on Windows the per-build MSI ProductCode is resolved at runtime from the stable WiX UpgradeCode and removed viamsiexec, with ansc deletefallback for non-MSI service layouts. The agent's retirement is finalized only on a reported success; a reported failure keeps the agent active (uninstall_status = failed) for retry, and a missing report is surfaced as awaiting confirmation. Unsupported layouts (non-packaged/manual installs, macOS, offline) return a clear fallback to unregister plus manual removal. Deployment (bootstrap) records gained a soft-delete lifecycle —DELETE /api/v1/deployments/:id(gated bydeployment:write, organization-scoped) invalidates the enrollment token and install script without affecting already-registered agents, and the public script/config endpoints then return 404. Deployment list responses use a dedicated token-freeDeploymentResponseDTO with a computedusableflag, while the create response returns the bootstrap token exactly once viaDeploymentCreatedResponse(the UI, Go SDK, and Terraform provider depend on it). The Deployment → Agents tab becomes an operational console (unregister with impact preview + reason, remote uninstall, re-register with one-time token, visible error states), and Deployment → Deploy gains delete, view-script, and clipboard-fallback actions. Finally, the agent module's owngo testsuite now runs in PR, dev, and release CI (previously only cross-compiled), and a filesystem-discovery policy-invalidation test that was root-fragile was made deterministic. - Rotation Templates Gain Policy Windows and Secret Custody Mode — Rotation configuration templates now carry
lead_time_days(days before expiry to start a certificate renewal),grace_period_days(days the previous value stays valid for rollback), andsecret_custody_mode(local,transient, ordelegated). These fields are exposed through the rotation template API, the Go SDK, and themazevault_rotation_templateTerraform resource, and are aligned end to end with the persisted catalog (migration000195). The rotation template API schema and its Swagger documentation were updated to describe the new fields. The template additionally exposesproject_id(optional project scoping) andretry_delay_seconds, and on the Terraform resourceorganization_idis nowOptional+Computed(server-resolved) with a single shared flatten path so create, read, and update cannot drift; these additions map to already-persisted columns and require no new migration. - Discovered Certificates: Search and Assignment Modes — The Discovered Certificates page adds a server-side
searchfilter and explicit assignment modes for adopting discovered certificates into management, including a bulk-adopt endpoint (POST /discovered-certificates/bulk/adopt, gated bydiscovered_cert:bulk) alongside the single-item adopt path. The standalone Certificate Discovery route was removed and now redirects to Discovered Certificates. - Actionable Rotation Status on the Dashboard — The Dashboard now resolves rotation items to their actionable destination through a new navigation resolver, so rotation status entries link directly to the surface where they can be acted on.
- Deployment Consolidated Under Enterprise Functions (PoC / Enterprise Gated) — Configuration Management, SSH Management, KeyTab Management, and Deployment now live together with Token Management under a single Enterprise Functions navigation group, which is a pure grouping header that only expands/collapses and never navigates on its own. Configuration, SSH, and KeyTab were already gated by their
config_management/ssh_management/keytab_managementlicense features; Deployment is now gated the same way through a newdeployment_managementfeature granted to PoC and Enterprise licenses (active, grace, or expiring state). The/api/v1/deploymentsmanagement group (create/list/delete) is enforced server-side withFeatureLicenseMiddleware, returning HTTP 403 for Small Business or unlicensed tenants, and the Deployment page renders an upgrade banner instead of the tabs; users still see the menu entry when they hold the matching RBAC permission. The unauthenticated, UUID-protected agent bootstrap endpoints (/deployments/:id/script,/config,/agent-binary) are intentionally left ungated so unattended agent installs keep working, and agent/gateway management endpoints are unchanged. mazevault-agent enrollCommand and Pre-Seed File —mazevault-agent enroll --server <https-url> --token <token> [--ca-file <path>] [--force] [--no-start]writes the configuration, copies a private CA file and enables the service in one step;--forcegives the agent a new identity (certificate, key and recovery token) — the server keeps the same agent record when the hostname and the machine ID match — and does not deleteca.crtor the pre-seed file. For automated installs the agent reads/etc/mazevault/enroll.conf(Windows:C:\ProgramData\MazeVault\enroll.ini) on start when noagent.yamlexists. See the Agent Deployment Guide.- Certificate Import: Documentation Link and Note at Import Time — The certificate import dialog (Review & Configure step) now accepts an optional Documentation URL and a free-text Note next to the existing Tags field, so this metadata can be captured during import instead of only afterwards on the certificate detail. The values are validated with the same rules as the detail editor (the documentation link must be an
http(s)URL of up to 500 characters; the note is limited to 256 characters) and are applied to every certificate created from the upload — including each certificate of an imported chain and every file in a multi-file import, matching the existing behaviour of Tags.
Improvements¶
- Secret Manager Integrations Support Azure Key Vault Only — The AWS Secrets Manager, HashiCorp Vault and GCP Secret Manager secret-manager providers have been removed; Azure Key Vault is the only supported secret manager. Creating, connection-testing or syncing one of the removed providers is rejected, and their key/secret offload and rotation targets are no longer offered. Existing integrations and rotation targets of the removed types are disabled by a migration (their rows are kept so their owners can review and delete them) and can still be read, updated and deleted. — Certificates signed from an uploaded CSR are stored with key custody
none; operators can now hand MazeVault the key afterwards from Certificate detail → Overview → Import private key (PEM key, encrypted PEM key, PFX/P12, or pasted PEM) with local or secret-manager custody, respecting Orchestrator Mode. No new endpoint was introduced: the dialog reusesPOST /certificates/import/file, and the new optionalexpected_certificate_idform field (also available onPOST /certificates/import) pins the request to that single certificate so unrelated material is rejected instead of creating or mutating another record. The multi-file import now pairs standalone.keyfiles with their certificate through the backendpreview-multimatching (newkey_source_filein the preview response) and sends certificate and key in one request, so a separately uploaded key reaches an already-managed certificate. The duplicate/attach lookup is now SHA-256-thumbprint-first (serial + issuer remains a legacy fallback that refuses rows whose stored thumbprint differs), the custody check honors external custody (an externally stored key is never silently replaced by a local copy), a project-scoped import can no longer mutate a certificate owned by another project, attaching a key never changes the certificate's renewal settings or downgrades a richer stored chain, and the "already exists" error now explains how to add the key. - GitOps and HSM Integrations Hidden for 1.0 — The GitOps integration type (GitHub, GitLab, Azure DevOps) and the HSM integration type (AWS CloudHSM, Azure Managed HSM), together with the DevOps Variable rotation target, are no longer offered. Creating, connection-testing or syncing one is rejected, and they are removed from the integration wizard and rotation-target selectors. Existing integrations and targets of these types are disabled by a migration (their rows are kept so their owners can review and delete them) and can still be read, updated and deleted. HSM Devices (Organization Settings) and GitHub / GitLab SSO keep their own features and are unaffected. GitOps and HSM are planned to return as extensions in a later version. — Certificates signed from an uploaded CSR are stored with key custody
none; operators can now hand MazeVault the key afterwards from Certificate detail → Overview → Import private key (PEM key, encrypted PEM key, PFX/P12, or pasted PEM) with local or secret-manager custody, respecting Orchestrator Mode. No new endpoint was introduced: the dialog reusesPOST /certificates/import/file, and the new optionalexpected_certificate_idform field (also available onPOST /certificates/import) pins the request to that single certificate so unrelated material is rejected instead of creating or mutating another record. The multi-file import now pairs standalone.keyfiles with their certificate through the backendpreview-multimatching (newkey_source_filein the preview response) and sends certificate and key in one request, so a separately uploaded key reaches an already-managed certificate. The duplicate/attach lookup is now SHA-256-thumbprint-first (serial + issuer remains a legacy fallback that refuses rows whose stored thumbprint differs), the custody check honors external custody (an externally stored key is never silently replaced by a local copy), a project-scoped import can no longer mutate a certificate owned by another project, attaching a key never changes the certificate's renewal settings or downgrades a richer stored chain, and the "already exists" error now explains how to add the key. - Unused session secret removed from the deployment configuration —
MAZEVAULT_SESSION_SECRET(SESSION_SECRETin the Compose kit's.env,global.keyVault.secretKeys.sessionSecretand the Key Vault secretmazevault-session-secretin the Helm chart) was required by the installers and the chart but never read by the backend. New installations no longer generate it, and the chart no longer reads it from Key Vault. Existing installations need no action: a leftover value in.env, Helm values or Key Vault is ignored and can be deleted. - Unused Console URLs and the Agent Discovery Results API Removed — The web interface no longer has the
/settingsplaceholder page ("This feature is currently under development") or the old URLs that only redirected to pages in the menu:/certificatesand/certificates/{id}(Certificate Dashboard),/password-requests(Password Requests),/notificationsand/conflicts(Synchronization Problems) and/discovery/certificates(Discovered Certificates). No link of the application led to them; an old bookmark now opens the dashboard. The Discovery Results page of an agent (/agents/{id}/discovery), which no link led to either, and its APIGET /api/v1/agents/{id}/discoveryare removed as well (a call now returns HTTP 404):GET /api/v1/discovered-certificates?agent_id={id}(needsdiscovered_cert:read) returns the certificates an agent discovered. The agent, the CLI, the Terraform provider and the Kubernetes operator did not call the removed API. An invalidagent_id,project_idormanaged_certificate_idonGET /api/v1/discovered-certificatesnow returns HTTP 400; it used to be ignored, so the call returned every discovered certificate. - Audit log archive destinations removed — The Organization Settings → System Outputs tab is now called Audit Log Streams and configures real-time streaming to Splunk, Elasticsearch and Syslog only. Archive destinations (AWS S3, Azure Blob Storage, File Share), the batch upload behind them, the
POST /organizations/{id}/integrations/test-archiveendpoint and the Prometheus metricsmazevault_archive_events_dropped_totalandmazevault_archive_upload_errors_totalwere removed. Migration000219_remove_audit_archive_destinationsdeletes the stored archive destination configurations, whose credentials were kept unencrypted. To keep audit history beyond the local retention, stream it to a SIEM. Remove alerts or dashboards that use the two metrics. Creating an organization integration now accepts only the categoriesnotificationandlog_streamand answers400for any other,archiveincluded. - Attach a Private Key to an Existing Certificate (CSR-Issued or Imported Without Key) — Certificates signed from an uploaded CSR are stored with key custody
none; operators can now hand MazeVault the key afterwards from Certificate detail → Overview → Import private key (PEM key, encrypted PEM key, PFX/P12, or pasted PEM) with local or secret-manager custody, respecting Orchestrator Mode. No new endpoint was introduced: the dialog reusesPOST /certificates/import/file, and the new optionalexpected_certificate_idform field (also available onPOST /certificates/import) pins the request to that single certificate so unrelated material is rejected instead of creating or mutating another record. The multi-file import now pairs standalone.keyfiles with their certificate through the backendpreview-multimatching (newkey_source_filein the preview response) and sends certificate and key in one request, so a separately uploaded key reaches an already-managed certificate. The duplicate/attach lookup is now SHA-256-thumbprint-first (serial + issuer remains a legacy fallback that refuses rows whose stored thumbprint differs), the custody check honors external custody (an externally stored key is never silently replaced by a local copy), a project-scoped import can no longer mutate a certificate owned by another project, attaching a key never changes the certificate's renewal settings or downgrades a richer stored chain, and the "already exists" error now explains how to add the key. - Uploaded CSRs Are Validated Against the Template Before the CA Is Contacted — Uploaded CSRs now fail fast at submission when they violate explicit template policy: the self-signature must verify, the key size must be in
allowed_key_sizeswhen configured (previously enforced only by the internal CA, never by ADCS or external CAs), and the SAN entries must satisfy an explicitsan_config(allowed_san_types,san_validation_pattern,max_san_count, and the newrequire_sanflag that rejects CN-only CSRs). Defaults are permissive by design — templates withoutsan_configaccept every CSR as before — and system templates (agent/gateway mTLS) are exempt. The requested SAN set and key parameters of an uploaded CSR are now recorded on the certificate request for auditability. - ADCS Manager-Approval Requests Are Tracked Instead of Failing — Issuing a new certificate through an ADCS CA that requires manager approval no longer returns HTTP 500 while the CA keeps the enrollment: the request moves to
submitted_to_caand is finalized automatically by the external order poller once the CA approves. CA providers can implement the new optionalIssuedCertificateFetcherinterface to return the issued leaf for an order ID; ADCS implements it, fixing a latent defect where the poller would have stored the CA chain as the leaf. - Certificate Request Lifecycle After Issuance Failures — An auto-approved request whose issuance fails is now marked
failedwith the error recorded (instead of lingering asapprovedwithout a certificate), and a manually approved request whose issuance fails is returned topendingso the approver can retry; a later successful issuance clears the recorded error. The request status enum documents thefailedstate and the UI shows it. - Canonical Certificate Serial Encoding —
certificates.serial_numberis consistently stored as the decimal big-integer string already used by OCSP, revocation and import lookups. ACME and HashiCorp Vault issuance, external order finalization and the built-in ACME server fast path previously wrote or queried hexadecimal serials, which broke import de-duplication and the ACME server's indexed lookup for those certificates. Vault revocation and status calls translate the canonical serial back to Vault's colon-separated hex format, so both legacy and normalized rows keep working. An idempotent identity backfill (BackfillCertificateIdentity) re-derives serial and thumbprints from the stored DER; it runs in the background on primary startup and is also part ofPOST /admin/certificates/backfill, which now reportsidentity_normalized. - Template Editor No Longer Flips "Allow Additional SANs" —
allow_additional_sanson the certificate-template create/update API is now presence-aware (omitted keeps the stored value; an explicitfalseis honored). Previously an update that omitted the field — which the template editor UI never sends — reset it tofalse. - Integration Group Scope Resolution for RBAC — A new
IntegrationGroupScopeMiddlewareresolves a standalone integration-group ID to its owning active project before project RBAC is evaluated, and rejects requests for groups whose project is archived or missing. This lets integration-group endpoints be authorized consistently with the rest of the project RBAC model. - SSH Authorized-Key Revocation Lifecycle — Agents can poll for pending authorized-key revocations (
GET /agent/authorized-keys/pending-revocations) and confirm completion (POST /agent/authorized-keys/:id/confirm-revocation), and operators can revoke an authorized key (POST .../authorized-keys/:id/revoke) and retry a failed SSH key deployment (PUT /ssh-keys/:id/deploy). A stopped or partially failed rotation execution can be resumed throughPOST /rotation/executions/:id/resume. The SSH key rotation confirmation message was also clarified. - Rotation Runtime Targets Only Route Through Active Agents — When a rotation delegates work to an agent (for example keytab or SSH deployment), the runtime now resolves the linked agent and refuses to route through an agent that is inactive, revoked, or soft-deleted, returning a clear error instead of proxying to a dead target.
- Rotation Template Numeric Field Validation — Rotation template numeric fields (
rotation_interval_days,lead_time_days,grace_period_days,max_retry_attempts,retry_delay_seconds,timeout_minutes) are now validated as non-negative integers across the backend API, the frontend, and the Terraform provider, with structured application errors instead of opaque failures. Theretry_delay_secondsfield — already persisted and exposed through the API, SDK, and Terraform resource — is now also editable in the rotation-template UI form, so it can be configured and viewed from the console. Bulk certificate adoption surfaces user-friendly messages for partial failures. - Graceful Backend Shutdown on SIGTERM — The API server now drains in-flight requests through
http.Server.Shutdownwhen it receives SIGTERM — with a drain deadline kept below the Kubernetes termination grace period — and then stops the log-stream and audit-archive background services before exiting, instead of being force-killed mid-request during rollouts.http.ErrServerClosedis treated as a normal shutdown. - SSH Authorized-Key Ownership Enforcement — Listing, deploying, revoking, and removing SSH authorized keys (and listing key pairs) now consistently enforce key-pair ownership — the acting user must own the key pair or hold
ssh:admin— matching the ownership checks already applied to get, export, and delete. A non-admin can no longer enumerate another user's key inventory or deploy/revoke/remove keys they do not own, and producer-side revocation and removal, plus the agent's revocation confirmation, now write request-ID-scoped audit records. - Rotation Resume Requires an Authenticated Actor —
POST /rotation/executions/:id/resumenow rejects a request without an authenticated principal with HTTP 401 before the orchestrator runs, and records both successful and failed resumes with full request-ID audit context. - Agent Recovery Token Stability (no re-registration lockout) — Agent re-registration no longer rotates a still-valid recovery token on every call. A fresh recovery token is minted only when the agent bootstraps/reinstalls with a deployment token or has no usable token on record; an agent that authenticates with its current recovery token keeps it. Combined with atomic, crash-safe agent-state persistence — the rotated token and identity are staged and committed in memory only after the durable write succeeds, and the temp-file replacement is now atomic on Windows as well (
MoveFileExwith replace-existing) rather than only on POSIX — an agent that crashes or fails to persist a rotated token can no longer be permanently locked out. This is a behavioral hardening only — no schema change and no API contract change. - Agent Registration Hardened (behavior change) — Agents now send a hashed machine ID. A deployment token can no longer re-register an agent that belongs to another organization (the request is rejected). Two machines with the same hostname but different machine IDs now become separate agents instead of overwriting each other (agents of this version; older agents keep working unchanged). An agent that lost its local state can still re-register with its original deployment token after the token expired, but only on the same machine and within the same organization. An agent's recovery token identifies it even when its machine ID changed (for example after a rollback to an older agent version), and a record of an older agent without a machine ID in another organization no longer blocks the hostname for an agent of this version.
Bug Fixes¶
- Destroying
mazevault_shared_secretrevokes the share link; shared secrets are importable — NewDELETE /api/v1/share/{id}deletes a share (only the user who created it; anyone else gets 404). The Terraform provider calls it on destroy and replacement, so the old link stops working. Import ID is now<share_id>/<secret_id>. - Number and list fields keep what you type; form labels are announced; template and project names are required — Number fields (e.g. priority, lead days, validity, intervals, password lengths) no longer snap back to their default when cleared, so typing
14stores 14 instead of3014; an emptied field keeps its last valid value instead of savingnull. Comma-separated list fields (Elasticsearch and Actuator endpoints, policy OIDs, visibility-rule scopes) keep typed commas and spaces, and typing a visibility rule ID no longer loses focus. Form labels, the audit-log filters and the compare-environments selects now have accessible names. The project-template wizard and Create Project refuse an empty name, and the template's Environments step has an explicit "All environments (including future ones)" choice: templates stored for all environments keep that on save, picking specific environments stores just those, and picking none now means no environment instead of all of them. - Agent reports failed install steps, resends lost task answers and stops promptly — A certificate sync whose
post_install_commandfailed no longer records the step as completed (the answer carriespost_install_error), and a Linux trust directory that takes no CA certificate is reported as a failed trust-store install instead of success. A task answer the agent could not send because the connection dropped is kept and sent again after it reconnects; this takes effect once the backend matches answers across connections, which a later backend update adds. Stopping or restarting the agent no longer waits 10 seconds for the task connection, an agent whose mTLS client key does not load stops with a configuration error instead of crashing later, and keystore passwords are passed tokeytoolandopensslthrough the environment instead of the command line, where every local user could read them. - The UI offers only actions your role allows; login errors and one-time secrets handled correctly — Buttons and pages now follow the same permission as the server: Password Requests needs
agent:admin(menu and page), license activation and renewal needbilling:write, rotation templates are edited and deleted withrotation:write, Add User on a project needsrole:assign, assigning templates and project settings needproject:write(without it the settings are read-only), integration changes needintegration:write, and the Entra ID dashboard needsintegration:readandentra:read(Sync needsentra:write). Pages no longer load data before checking access. Withoutagent:admin, the certificate deployment-target editor offers the agents bound to the certificate's project. An encryption failure after MFA is no longer reported as an invalid MFA code, and a failed LDAP or MFA login shows its own error. A cancelled password-request approval no longer keeps the typed password, a revealed managed token is masked until you click Show, and a newly created client secret or API token is dropped when its dialog closes. - Dialogs keep your input on errors; saves no longer drop project tags, webhooks, descriptions or CA URLs — The incident-contact dialog and the new-environment form stay filled when saving fails, a failed ignore of a discovered certificate and a failed first load of domain validation are shown, and managed-token errors without a server message name the failed action. Saving project settings keeps the project's tags and notification webhooks, editing a service identity keeps its description, and clearing the OCSP or CRL URL of a CA removes it. The rotation-history button of an Entra credential shows that credential's history, Bind Agent shows the agent's OS, managed tokens can be deployed to AWS Secrets Manager, and an environment group mapping is created for the identity provider you choose (Identity Provider field). The system certificate upload no longer offers backup and reload options, which the server never applied. Moving a rotation target earlier or later now works when targets share a priority, a certificate with two post-rotation actions of the same type no longer saves the edited one twice, and changing a secret rotation target's type no longer sends the old type's settings. Usage and Billing shows real project and secret usage (needs
org:read), and a dismissed license expiry notice stays dismissed after a reload. Rotation templates and keytabs are deleted only after an in-app confirmation, the MFA settings follow edits of the raw JSON, a gateway can be assigned as DR standby to an environment another gateway is primary on, the agent list is in English and shows "Never" for an agent that has not reported yet, and the certificate details no longer stay on "Loading...". - Creating records without optional fields no longer fails — A rotation template or an integration group created without its optional lists (e.g.
notify_before_days,mappings) and an approval policy created withoutconditionsanswered500; they are now stored with empty values (existing approval policies withconditions[]are converted to{}). Switching an organization tointermediateorproxyPKI mode now really registers the upstream CA account (pending validation), and recorded rotation replay metadata without ametadatafield is no longer dropped. - PostgreSQL session listing and drain work; rotation failures show superseded runs and linked incidents — Listing and draining the sessions of a PostgreSQL integration answered
500for every TCP session, so password rotation with session drain could not finish. On the dashboard, a rotation failure followed by a successful run was never marked as superseded and never linked to its open rotation-failure incident. - Temporary access and agent–project bindings work beyond the first record — Temporary access grants (including break-glass) and agent–project bindings were stored without an id of their own, so only the first one in the whole system could be created: the second grant and the second binding failed with an error, and revoking a grant failed too. Each record now gets its own id; a record created earlier keeps working.
- Rotation Delivery and Cleanup Steps Fail Instead of Reporting Success (check rotation configs before upgrading) — Several rotation steps reported success without doing their job; they now fail the step, so the rotation fails visibly (and is compensated) instead of being published with a target still holding the old value.
post_rotation_syncstill updates every reachable Key Vault but fails when a configured integration cannot be resolved (deleted or disabled, gateway resolution error), has novault_urlor no usable credential; the rollback of a rotation run on the MazeVault server then also restores the previous value in the vaults the failed step had already updated, also when a vault write itself failed (a step delegated to a gateway is not covered yet; before, a failed step was never compensated, andpost_rotation_synccompensation found no secret key in rotations run on the MazeVault server, so it restored nothing).certificate_to_keyvaultfails for a provider it does not support (for examplegcp_secret_manager) instead of "simulating" the push.spring_actuatorfails when any configured endpoint did not refresh (HTTP error, unreachable, TLS). The Kubernetes pod trigger now honourslabel_selector: it restarts every deployment, statefulset and daemonset matching the selector and fails when nothing matches; its service account needslistandpatchondeployments,statefulsetsanddaemonsets(API groupapps) in the namespace, even if only deployments match. Thecleanupstep has no cleanup implementation, so a configuredtargetis now rejected as not supported instead of being reported ascleaned: true. Sync now on a secret's deployment target (POST /api/v1/secrets/{id}/rotation/targets/{targetId}/sync) now delivers the secret's current value to that target immediately and answers200with the target carrying the real result (last_delivery_statussuccessorfailedwithlast_delivery_error); before, it only set the status topending, which never changed. Database targets get the admin credentials of their integration as in a rotation, and the delivery has the same time limit as a rotation step (timeout_seconds, default 5 minutes). A target that cannot be synced (role other than distribution, or a target type without a delivery step) is refused with409and its delivery state is left unchanged; so is a target whose integration, agent or target project lies outside the secret's project or organization, checked as for a rotation step. The web interface shows a failed sync with its error. The manual sync runs on the MazeVault server, not on a gateway: it fails for a target reachable only through a gateway, and in an environment that routes rotations through a gateway, a target the server can reach is written by the server. - Entra post-rotation delivery completes — Delivering a rotated Entra client secret to its post-rotation targets no longer ends as a failed execution (with rollback and a propagation-failure notification) after all targets succeeded, and a target with a long name (e.g. a webhook with a long URL) is no longer silently left out of the delivery: if a delivery step cannot be stored, the delivery fails and the failure notification is sent.
- Naming Convention: Parsing and Provisioning Work With the Default Convention —
POST /api/v1/naming-conventions/{id}/parseand/provisionanswered500for every name of the default convention (variablesprostředí,číslo), and/cross-validatereported every valid default name as violating its allowed characters. Both now work; an emptynon_prod_prefixno longer makes every environment non-production. - Gateway failover keeps one active gateway per environment — When a failed primary gateway sent heartbeats again while its DR gateway was serving the environment, the health monitor reactivated the primary, so two gateways were active (the check looked for the wrong DR role); the primary now stays
faileduntil you run failback, also when the DR gateway serves the environment through its supported environments. The gateway health endpoint now really queries the database, so a gateway whose database is down reportsdegradedinstead ofhealthy. Routing now picks the gateway with the lowestfailover_priorityacross single- and multi-environment gateways (a single-environment gateway used to win regardless). The DR failover runbook now states the real thresholds: a gateway without a heartbeat for 2 minutes stops receiving work after its fast retries (about 5 minutes) and is markedfailedonly after 7 days; to fail over sooner, deactivate the primary first. - Agent File Sync Keeps Backups Private and Edits Files Safely — Before a secret sync overwrote a config file, the agent saved its backup (
.bak.<time>) readable by every local user, even when the file itself was private; backups are now created with owner-only access, and updated or restored files keep their original permissions and are replaced atomically via a temporary file. A sync into an empty YAML file or a JSON file containingnullno longer crashes the agent. For.envfiles a secret value containing a line break is rejected instead of injecting another variable, andexport KEY=lines are updated in place (the old secret no longer stays behind). On Windows, files inherit the permissions of their directory. - Discovery Results Can Be Adopted or Ignored and Consistency Warnings Resolved —
POST /api/v1/discovery-results/{id}/adoptand/ignorefailed with an error on every request, andPOST /api/v1/consistency-warnings/{id}/resolvealways returned 500. Both now work and record the signed-in user as the actor; the same fix makes project environment changes record who made them. - Post-Rotation Actions Run for Gateway Certificate Rotations and Record an Aborting Failure — A certificate rotation delegated to an environment gateway now runs the configuration's post-rotation actions (webhook, application reload, notification) after the workflow succeeds, as the local path already did; before, they never ran. During a certificate renewal the post-rotation actions run exactly once, in the renewal completion; the post-renewal deployment no longer runs them a second time. A secret post-rotation action with
on_failure: abortthat fails now stops the remaining actions and marks the execution failed verification / operator action required, storespost_actions_completed, marks the rotation config failed and opens a rotation-failure incident, ascontinueandwarnalready did; before, the rotation looked fully successful. - Rotation resume waits for a running rotation, a finished execution is not run again, a partial rollback stays visible — Resuming a failed rotation execution (
POST /api/v1/rotation/executions/{id}/resume) now also takes the rotation lock of its configuration and is refused while another rotation of the same secret or certificate runs, so the two can no longer generate and write two different new values. A pre-built execution (Entra ID post-rotation delivery) runs only while it ispending; a second run of a completed or failed execution is refused instead of executing every step again (for Entra ID, another credential). When a step fails and some compensations fail too, the execution keeps the statuspartially_rolled_backinstead of being overwritten withfailed, so executions that need manual repair are visible and can be resumed; Rotation Problems lists them (and they can be acknowledged there), and the dashboard and compliance report count them as failed rotations. - ACME Server Serves Real Clients and Revocation Reaches the CA and Inventory — The built-in ACME server (
/api/acme/*) no longer answers every POST with403 CSRF token mismatch: its protocol routes are exempt from the browser double-submit check because every request is JWS-signed (new-noncechanges no state), so cert-manager, certbot and other clients without cookies are served. Certificates issued through an internal CA account are now stored with that CA (ca_id), sorevoke-certrevokes them at the internal CA instead of failing with500 certificate not found; migration 000260 fills inca_idfor certificates issued that way before. After the CA has revoked a certificate, the inventory certificate is markedrevokedtoo (with revocation date and reason), not only the ACME order. When the order's CA account cannot be loaded,revoke-certnow fails with500 serverInternaland leaves the order valid instead of reporting a revocation that never reached the CA. - Key Vault RBAC Access Shows Only the Signed-In User's Own Roles —
GET /api/v1/azure/keyvaults/discover,POST /api/v1/azure/keyvaults/check-accessand the rotation preflight's Key Vault write check counted every principal's role assignment on the vault as the signed-in user's, so a user with Key Vault Secrets User was reported as able to write and delete secrets whenever, for example, MazeVault's managed identity was Secrets Officer on the same vault. Effective access and the returnedrole_assignmentsnow contain only the user's own assignments on the vault and the scopes above it (resource group, subscription, management group), including those granted through Entra groups; assignments on a single secret below the vault no longer count as vault-wide access, and other principals' assignments are no longer returned. - Service Identities Pass the Device Check — The zero-trust device check on
/api/v1/secrets,/api/v1/rbacand/api/v2refused every request of a service identity (it tried to record the identity as a user's device). A service identity now passes the device check; its role assignments decide what it may do, and the anomaly check still applies. - ACME: External Account Binding, Wildcards and Health Check — ACME accounts with
eab_kid/eab_hmac_keynow send the RFC 8555 §7.3.4 external account binding on registration, so CAs that require it (ZeroSSL, Sectigo, Google Trust Services) accept the account instead of answeringexternalAccountRequired; an incomplete or non-base64url binding fails before any request. Wildcard authorizations are recognised by thewildcardflag the CA sends (RFC 8555 §7.1.4), so the defaultautopolicy validates them with DNS-01 on the base domain instead of failing with "no http-01 challenge found". The CA account status check now contacts the ACME directory on every check instead of reporting a cached result during an outage. - Terraform Handles Objects Deleted Outside Terraform the Same Way for Every Resource (check SDK callers) — When an object managed by Terraform was deleted in MazeVault,
terraform planfailed with a "not found" error for most resources instead of planning to recreate it, andterraform destroyfailed for most resources instead of finishing. Now every resource follows one rule: a404on refresh removes the resource from state (the next plan recreates it), a404on destroy counts as already deleted, and any other error (401,403,5xx, network) is reported and keeps the resource in state.mazevault_hsm_deviceandmazevault_shared_secretused to drop the resource from state on any read error, so a temporary backend failure planned a new HSM device; they now report the error. In the Go SDK,GetApprovalPolicy,GetDeployment,GetConfigTemplate,GetGroupMapping,GetRole,GetOrgProjectTemplateandGetSyncRulereturn a 404*APIError(IsNotFoundError(err)is true) for an id that does not exist instead of(nil, nil); code that checked the result fornilmust checkIsNotFoundError(err)instead. - Terraform Plans Nothing After a Refresh When Optional Attributes Are Unset or Empty — When an optional attribute was left out of the configuration,
Readstored the backend's empty value or its default ("",false,viewer,daemon,agent,pull,incremental,manual_resolution,continue), so the nextterraform planshowed a change after every refresh. Formazevault_user(role, andemailwritten with upper-case letters, which the backend stores in lower case),mazevault_user_role(project_id,environment) andmazevault_deployment(agent_mode,deployment_type,gateway_url) that change replaced the object on every run (a deployment replacement issues a new agent token).Readnow keeps an unset attribute unset and a configured""as"", a value the backend fills in by default no longer counts as a change, and""and an unset value no longer force a replacement. The same applies to config_template, consistency_group, identity_provider, integration_group, keytab, rotation_config, secret_rotation_target and sync_rule, and to the optional fields of post-rotation actions (on_failurethe backend sets tocontinueincluded).mazevault_user.role,mazevault_deployment.agent_mode/deployment_typeandmazevault_sync_rulesync_direction/sync_mode/conflict_strategynow show the server's value when not configured; removing one of them from the configuration keeps the current value. Updating an integration group or consistency group without adescription, or a rotation workflow withouttarget_environment, no longer fails with "Provider produced inconsistent result after apply". The first apply ofmazevault_caandmazevault_rotation_configno longer fails with "unknown value after apply" when the server leavesaccount_id,key_algorithm,last_errorortarget_environmentempty, and alast_errorthe backend cleared leaves the state. Post-rotation actions removed in MazeVault now also leave the state at refresh (rotation_config, rotation_workflow, certificate_rotation_config, entra_rotation_config), soterraform planshows the drift and puts them back. Changingauto_updateof an existingmazevault_deploymentnow fails at plan time with an explanation (the API cannot change it) instead of an inconsistent result after apply. After the upgrade, a state written by an older provider version can show a one-time in-place change from"",false(auto_update) or0(post-actionorder) to unset; it does not replace anything and does not come back after one apply. - Entra ID certificate credentials can be rotated — Adding and removing a certificate credential of an Entra app registration (certificate rotation, staged secondary, deleting the credential) called Microsoft Graph
addKey/removeKeywithout the required proof of possession, so Graph rejected every call. MazeVault now signs the proof with the private key it stores for one of the app's currently valid certificates; when it holds none (e.g. a certificate uploaded outside MazeVault or an expired one), it updates the app'skeyCredentialsinstead, which needs no permission beyond what MazeVault already requires (Application.ReadWrite.OwnedByfor apps it owns, orApplication.ReadWrite.All). MazeVault serializes these updates per app, also across replicas, and checks the result afterwards. A change someone makes to the same app's certificates in the Entra portal at the same moment is not covered by this and can be lost, so do not edit an app's certificates in the portal while MazeVault rotates them. Graph errors also keep their HTTP status: 429/502/503/504 answers are retried by MazeVault's own backoff and 401/403/404 are reported as authentication, permission and not-found errors instead ofunknown. - Entra ID credential lifecycle reports Microsoft Graph failures — When Graph refused to remove an old credential after its grace period (for example 403), MazeVault still marked it cleaned up and expired although it kept working in Entra, and never retried; it now stays in its grace period, the removal is retried on the next hourly run, and a critical
entra.credential.cleanup_failednotification names the error category (auth, permission, …); it is sent on the first failure and then at most once per 24 hours per credential (migration000249addsentra_credentials.cleanup_failure_notified_at). The credential is marked cleaned up without a notification only when Graph returns the app and the key is no longer on it (for example removed in the portal); an app the integration can no longer see (deleted, ownership removed, another tenant) keeps the credential in its grace period, and the notification says so. The rotation dry run'sentra_connectivitycheck now reads the app registration through Graph instead of only building a client, so a revoked integration secret or a missing permission fails the dry run (for gateway-delegated integrations the check is unchanged). A sibling credential stuck inrotatingfor over 30 minutes without an open execution is released by the next rotation again (the check usedupdated_at, which every sync refreshes; it now usesrotation_started_at, like the watchdog; credentials stuck since before migration 000175 are still left to the watchdog). The expiry monitor now sends the 7-day critical notice: to a credential first seen with under 7 days left, and once to a credential already warned at 30 days when it crosses 7 days (a monitor run missed at that moment skips it). The connection test of themanaged_identityandworkload_identityauth methods now requests a Graph token (within 5 seconds) instead of only building the credential, so it fails off Azure or with a wrong client ID. - Agent no longer crashes on certificates without a name and with a short serial number — A certificate without CN or SAN whose serial number has fewer than 8 digits made the agent panic in the sync loop when it built the file name; it now uses the whole serial.
- Kubernetes Operator Overwrote Secrets It Did Not Own — When a Kubernetes Secret with the name of a
MazeVaultSecretalready existed, the operator wrote the MazeVault value into it even if it belonged to someone else. It now writes only into a Secret that carries its controller owner reference to thatMazeVaultSecret(set on every Secret the operator has created, so Secrets created before the upgrade keep syncing); any other Secret, including one that only has theapp.kubernetes.io/managed-by: mazevault-operatorlabel, is left untouched and the resource gets the conditionSynced=Falsewith reasonSecretConflict. The conflict is detected before the value is fetched from MazeVault. Rename or delete the conflicting Secret to resolve it; sync then resumes on the operator's next retry (retries back off up to about 17 minutes), or right away when theMazeVaultSecretis changed. Whenspec.secretKeychanges, the Secret now holds only the new key; the value under the previous key is removed. - Kubernetes Operator:
MAZEVAULT_URL, error handling and status —MAZEVAULT_URLmay now be the plain server URL (https://mazevault.example.com); the operator adds/api/v1itself (a URL that already ends in/api/v1keeps working; before, only the full API URL worked and the bare URL ended in404). A404or403answer of the backend (the backend answers404for any lookup error and403for a policy denial) setsSynced=Falsewith reasonFetchFailedand is retried at therefreshIntervalinstead of at the error backoff; other errors still back off. The backend's response body is no longer copied into theSyncedcondition message or the operator log, only the HTTP status. The status ofMazeVaultSecretgainsobservedGeneration(also on the condition); a failed sync never moveslastSyncTime. - OCSP Responder Answered No Standard Client and No Backend Certificate — The standalone OCSP responder (
mazevault-ocsp) indexed CAs by a hash of the whole public key structure instead of the RFC 6960issuerKeyHash(hash of the public key bit string), so requests from standard clients (OpenSSL, browsers, Gox/crypto/ocsp) gotunauthorized; and it readcertificates.revocation_reason, which the backend fills with a reason name or an empty string, as a number, so every certificate created by the backend gotinternalError. It now matches standard requests, reportsgood/revokedfrom the revocation date, takes the RFC 5280 reason code from the certificate's revocation entry, no longer serves soft-deleted CAs, refuses to sign with a CA certificate outside its validity period (internalError, logged) and logs every CA row it cannot load. - Role Assignments Created Through the Go SDK or Terraform Were Global (review them) — The Go SDK (and so the Terraform resource
mazevault_user_role, which uses it) sentproject_idandenvironmentat the top level of the role assignment request, while the backend reads them from the nestedscopeobject, so every role assigned this way was granted globally instead of being limited to the project or environment. The SDK now sends the scope in thescopeobject (AssignRoleRequest.Scope, which replaces the top-levelProjectIDandEnvironmentfields: SDK users must adapt). Assignments created through the SDK or Terraform before this release are global: review them (Users → roles, orGET /api/v1/rbac/users/{id}/roles) and re-create the scoped ones. - Go SDK Sign-In and Token Refresh Did Not Work —
LoginandRefreshTokencalled/auth/loginand/auth/refresh, while the backend serves/api/v1/auth/loginand/api/v1/auth/refresh, so both ended with 404. The SDK client also had no cookie jar, so therefresh_tokencookie set at sign-in was never sent back andRefreshTokencould not succeed. Both now call the real routes,NewClientkeeps the cookie (a client that replacesHTTPClientmust set its ownJarto refresh), andLoginResponse.User.MustChangePasswdis read frommust_change_password, so a forced password change is reported. - Go SDK Calls Only Routes the Backend Serves —
ListProjectCSRscalled/api/v1/projects/{id}/certificate-requests, which does not exist, and now calls/api/v1/projects/{id}/csr, so the Terraform data sourcemazevault_project_csrsworks. The backend has no route to create a certificate template in a project or to delete an organization, soCreateProjectCertificateTemplate(now deprecated: create the template withCreateOrgCertificateTemplateand assign it withAssignCertificateTemplateToProject) andDeleteOrganizationnow fail fast: they send no request and return an error wrapping the newErrNotSupported(check witherrors.Is);terraform destroyofmazevault_organizationrecognizes it and removes the resource from state with a warning, the organization stays in MazeVault. - Go SDK Reads the Backend's List Responses —
ListKeytabsfailed with a JSON error (it expected a bare array, the backend answers the paginated{"data": [...], "total", "page", "limit"}envelope), andGetRotationResourceHistoryandListSyncRulesfailed the other way round (they expected{"executions": [...]}and{"rules": [...]}, the backend answers a bare array);GetSyncRuleis built onListSyncRulesand failed with it. All three now decode what the backend sends, so the Terraform resourcemazevault_sync_rulecan be read, imported and refreshed again and the data sourcemazevault_rotation_resource_historyreturns the history.ListKeytabsandListManagedTokens(and so the data sourcemazevault_tokens) now read every page instead of only the first one (25 keytabs, 50 tokens).ListAuditLogsResponse.Totalheld the length of the returned page, not a total; the audit-log endpoints return no total, so it is now always0and deprecated — page withlimit/offsetuntil a page holds fewer thanlimitentries. The unusedListRotationResourceHistoryResponseandListSyncRulesResponsetypes are deprecated. - Go SDK Sends and Reads the Backend's Field Names (check SDK callers and the first Terraform plan) — Many Go SDK models used JSON names the backend does not know, so values were silently dropped or never filled. They now match the backend DTOs: approval policies (
required_approvers, plustrigger_type,conditions,allowed_approver_roles/users,auto_expire_hours), config templates (template_typeand a JSON-objectdefinitioninstead offormat/template/variables), keytabs (keytab_dataandnotesinstead ofkeytab_base64/description, soImportKeytabno longer fails with 400), certificate templates (cert_type,validity_days), group mappings (provider_id,group_external_id,group_display_name,source, …), rotation workflows (rotationIntervalDays/postActionsread,post_actionssent), rotation executions and rotation history (error_message), shared-secret metadata (has_password,source_type) and the create response (link), project settings (id), project CA expiry (not_after), the renewal queue (scheduled_for,created_at), sync rules (key_transformobject), CA accounts (auto_discover,auto_renew,renewal_lead_days,sync_interval_minutes) and managed tokens (metadata).UpdateRotationConfigRequestgainsEnvironment(without it a manual trigger fails the preflight),UpdateRenewalPolicycan now switchauto_approveandkey_reuse_enabledoff (both are always sent), andGetRotationResourceHistoryWithLimitreads more than the backend's default 20 executions. Go code keeps compiling: fields without a backend counterpart are kept but deprecated, and most are no longer sent. Code that relied on the old (wrong) wire names, e.g. a hand-written fake server, must use the backend names.CreateRenewalPolicyRequestnow always sendsauto_approveandkey_reuse_enabled: a partialUpdateRenewalPolicythat reuses the struct without setting them switches both off, so fill in the current values first. LikewiseCreateSyncRuleRequestalways sendskey_transform: anUpdateSyncRulethat reuses the struct withoutKeyTransformclears the rule's key transform. Terraform:mazevault_approval_policydeprecatesenvironmentsandapprovers_group_id(kept in state, not sent);mazevault_config_templatesendsformatastemplate_typeandcontentasdefinition(a JSON object, usejsonencode);mazevault_group_mappingsendsgroup_nameasgroup_external_id;mazevault_sync_rulesendskey_transform_templateaskey_transform.template; the data sourcesmazevault_project_cas,mazevault_project_certificate_templates,mazevault_renewal_queue,mazevault_rotation_executionsandmazevault_rotation_resource_historynow return the CA expiry, template type and validity, queue time and failure reasons, andmazevault_rotation_resource_historygains an optionallimit. Action required on upgrade: values that were silently dropped so far start to take effect on the firstterraform apply—mazevault_approval_policy.required_approvals(the backend default was used until now),mazevault_sync_rule.key_transform_template(key names in the target are renamed by the template on the next sync; removing the attribute now clears the transform),mazevault_rotation_workflow.post_rotation_actions(the actions now run after each rotation) andmazevault_keytab.description(stored as the keytab notes). Review the plan before applying.mazevault_group_mappinghas a new requiredprovider_id(the backend rejects a mapping without it); add it to every mapping — setting it on an existing mapping does not re-create the mapping only when it equals the mapping's current provider (read from the backend); a different value re-creates it.mazevault_config_templatevalidatesformatand thatcontentis a JSON object at plan time. - Go SDK Escapes Query Values, Calls the Registered Collection Paths and Reports Real Consistency Status (check
GetConsistencyStatuscallers) —GetSecretandListRotationResourcesinserted the key, kind and environment scope into the query unescaped, so a value with&,#,+or a space sent a different request (another key, a cut-off value); every query value is now escaped. Collection calls (/api/v1/secrets/,/projects/,/organizations/,/users/tokens/,/certificate-templates/) now use the path the backend registers, with the trailing slash, instead of relying on its redirect (two requests per call, and a proxy that turns the 307 into a 301 would change a POST into a GET).GetConsistencyStatusreportedwarningwithMissingCount= number of groups for every project that had any consistency group; it now reports the worst last-check status of the groups (healthy,warning,error), one issue per unresolved warning (<group>: <key> in <environment>: <issue>) andMissingCount= warnings of typesecret_missing. The Terraform data sourcemazevault_consistency_statusreturns the same values, so a project whose groups have no findings is nowhealthy. - Terraform:
share_urlIs Sensitive, Environment Adoption Respects the Plan,validity_periodIs Validated (reviewterraform plan) —mazevault_shared_secret.share_urlis now sensitive: the link gives access to the secret and was printed in plan output and CI logs; outputs that expose it must be markedsensitive = true(or usenonsensitive()).mazevault_environmentadopts an existing environment with the same name or slug (the backend refuses the duplicate) only when the configuredis_productionandincident_auto_escalationmatch it; before, it took over the existing flags and reported success, so a production environment stayed production although the configuration said otherwise. The apply now fails and names the differing flags: import the environment or change the configuration.mazevault_certificate_template.validity_periodmust be a whole number of days, written as<n>d(e.g.90d, now accepted) or in hours (e.g.2160h); a value the provider could not parse (e.g.90dbefore,1y) used to be silently left out, so the template got the backend's default validity, and a duration that is not whole days (e.g.36h) was truncated to whole days (1 day); both now fail at plan time (90dis accepted).mazevault_integrationrestoresproject_idandenvironmentfrom the server on refresh. - Terraform Provider: Drift and Destroy Handling —
mazevault_secret,mazevault_project,mazevault_certificateandmazevault_renewal_policydeleted outside Terraform are planned for re-creation instead of failing the refresh with404.mazevault_rotation_configno longer fails with "unknown value after apply" (status,last_error,target_environment) and no longer shows a perpetual diff for an omittednotification_emailsorschedule. Destroying amazevault_certificateissued through an external CA account, which MazeVault cannot revoke, archives the record (with a warning) instead of failing. - Onboarding: Master Key Status Lost After Organization Setup — Generating the self-signed TLS certificate during organization setup saved the organization with a stale in-memory copy and cleared
master_key_encrypted, so the bootstrap state reported the master key as not generated. The organization is reloaded before the TLS step. - License Changes Did Not Reach the Primary at Validation — The primary read the license server's
/api/v1/validateanswer under field names the server does not send (licenseType,expiresAtinstead oflicense_type,expiration_date), so the validation at startup and then daily never updated the stored license. A license type changed on the license server (for example POC to Enterprise) or an extended term now reaches the primary at the next validation; restart the backend to apply it at once. - Project CSR approvals showed empty subjects and ignored the status filter — The CSR tab of a project now shows the requested common name, organization, organizational unit and country of each request (it read fields the API does not send, so the approver saw only the PEM).
GET /api/v1/projects/{id}/csrnow honours the optionalstatusquery parameter (for example?status=pending); without it all non-archived requests are returned as before. Approve and Reject are offered only for pending requests. - DigiCert: issued certificates were never picked up, DNS validation was refused — The DigiCert CertCentral connector read the certificate ID of an order from a top-level
certificate_id, while CertCentral returns it ascertificate.id, so an asynchronously issued DigiCert order never became available for download and discovery found no DigiCert certificates. It now reads the nested ID. A certificate template with DCV methoddnsis now sent asdns-txt-tokeninstead ofdns-txt, which CertCentral rejected. - ADCS: web enrollment and CES (WCCE) enrollment work against real servers — Web enrollment posted the request to
certrqxt.asp, which only shows the request form, so ADCS never processed it; it now posts tocertfnsh.asp, and a request waiting for manager approval keeps its request ID ("Your Request Id is 77."), so the approval poller can pick the certificate up. CES (WCCE) enrollment now reads the issued certificate fromRequestedSecurityToken/BinarySecurityTokenand the CA request ID fromRequestIDas MS-WSTEP defines them, and polls a pending request withQueryTokenStatusinstead ofRenew; the response form accepted before still works. Username, password and template name are XML-escaped in the SOAP request, so a password with&or<no longer breaks enrollment, and the CSR is sent as DER, as MS-WSTEP requires (before, the PEM text was sent). The CA certificate and chain downloads accept the PEM form certsrv sends forEnc=b64. - Linux Agent Could Not Run on Hardened or RHEL 8 Hosts — Two independent defects stopped the Linux agent on customer hosts. (1) The release agent binary was built with cgo enabled, so it was dynamically linked against the build machine's glibc and failed on RHEL/Rocky/AlmaLinux 8 with
/lib64/libc.so.6: version `GLIBC_2.34' not found; the agent is now built withCGO_ENABLED=0 -trimpathand is statically linked, running on any glibc. (2) The deployment install script placed the binary under/var/lib/mazevault/bin; on hosts that mount/varnoexec(CIS/STIG baselines) systemd failed withstatus=203/EXECin an endless restart loop. The installer and the rpm/deb package now install the binary to/opt/mazevault-agent/bin(owned by the agent user, listed inReadWritePathsso self-update keeps working, SELinuxbin_t). The installer was reworked for hardened hosts:set -euo pipefail, preflight (noexeccheck of the binary directory viafindmnt, SELinux detection, required tools), nocurl -kfallback any more (with a MazeVault CA the download uses it and falls back to the system trust store, never to insecure), the HTTP status and the server's error body are printed when the download fails (e.g.503 agent binary downloads not configured), acurlfailure after HTTP 200 (truncated transfer) counts as a failed download, and the signed binary is staged asmazevault-agent.newand executed asmazevault-agent(version) before it replaces the installed binary and before the unit is written, so anoexecmount, an SELinux denial or a glibc mismatch stops the installer with a clear message, leaves a previously installed agent untouched and never causes a restart loop,agent.yamlis written0640,systemctl restartis used so a re-run updates a running agent, hosts installed with the previous layout are migrated (old binary removed,ExecStartdrop-in overrides removed, other drop-ins kept), and exit codes are2preflight /3download or verification /4service not running (status and journal printed with tokens and UUIDs redacted). When the server has no CA configured, the installer no longer writes an emptyca.crtand the generatedagent.yamlleavesserver_ca_fileempty, so the agent validates the server with the system trust store; the Windows installer likewise skips writing and importing an empty CA. The agent's self-update and the remote-uninstall runner now choose a directory that is writable and not on anoexecmount (binary directory, state directory, then the temp directory) instead of assuming/tmpis executable, and report the rejected directories when none qualifies. Remote uninstall recognises script-installed hosts (no rpm/deb package): the unit, drop-ins and the agent directories are removed directly instead of a failingrpm -e, and stopping the service, removing the unit file and removing/opt/mazevault-agentare required steps whose failure is reported to the server instead of a false success,/opt/mazevault-agentis removed only when the binary actually lives there, and the root requirement is explained in the error. New optional variableMAZEVAULT_CA_FILE(release kit, installers,check-config.sh, Helm values, documentation) names the CA embedded into install scripts; the Compose kit mountsCUSTOM_CERT_DIRinto the backend as/custom-certsfor it. Operators who worked around203/EXECwith a drop-in pointing to/usr/local/binonly need to re-run the install script. - Compose Kit Did Not Start: Database Without TLS, Docs Without HTTPS — With the default
MAZEVAULT_ENV=productionthe backend refuses a database connection without TLS, but the kit's bundled PostgreSQL ran without TLS (sslmode=disable), so the backend never became healthy; the docs container only listened on port 80 while the kit published and health-checked HTTPS. The kit's PostgreSQL now uses TLS with the certificate from thecertsvolume and the backend and OCSP responder connect withsslmode=require; the docs container serves HTTPS on the kit's docs port (DOCS_PORT, default 8088) when a certificate is mounted and plain HTTP on port 80 otherwise (Helm unchanged). Existing Compose installations pick this up when the new kit's installer is run, which installs itsdocker-compose.ymland keeps the existing.envand data volumes (upgrade-mazevault.shalone does not replacedocker-compose.yml). - CRL Download in DER Returned an Empty Body —
GET /api/v1/ca/{id}/crl(defaultformat=der) answered200with DER headers but no content; onlyformat=pemreturned the CRL. The endpoint now returns the DER-encoded CRL, decoded from the stored PEM. - CRL Numbers Repeated and the Served CRL Could Be Stale — CRLs regenerated after a revocation took their number from a separate counter, so CRL numbers of a CA repeated and went backwards (RFC 5280 §5.2.3), and
GET /api/v1/ca/{id}/crlcould keep serving an older CRL after a newer one was generated. All CRLs of a CA now share one increasing number, continuing after the highest number issued so far; it is allocated atomically in the database, so concurrent regenerations on several replicas never reuse a number. - Built-in Roles Lost Permissions Granted by Upgrades — On every start the backend reset the permissions of built-in roles to an older hardcoded list, so permissions added by upgrade migrations disappeared after the first restart:
report:read/report:write,keytab:read(User, Secret Manager),dashboard:write,agent:admin,audit:read,config:readandproject:write(Certificate and Secret Manager), andtoken:read. Customer changes to built-in roles were overwritten the same way. The backend now only creates missing roles and never changes existing ones; migration000207_restore_system_role_permissionsrestores the intended permissions. It also grantstoken:read/token:write/token:deleteto Project Admin and Secret Manager (migration000193had granted them to roles that no longer exist). The migration only adds permissions and never removes any, so existing role assignments and customer edits stay in place. - Agent Keystore Deployment Sent a Bundle the Agent Could Not Read — The orchestrated
agent_keystore_syncstep handed the agent a singleexported_datablob, while the agent'sCertificateSyncBundleexpectscertificate_pem,private_key_pemandchain_pem; every JKS / PKCS#12 / Windows-store rotation therefore failed on the agent withfailed to decode certificate PEM, and the CA chain never reached the trust store. All deployment consumers (Kubernetes secret, Key Vault, agent keystore, agent file, Oracle wallet) now split the export with one shared helper — first certificate = leaf, remaining certificates = issuer chain, key separate — that also accepts the base64 form produced by a gateway round-trip, and the keystore step sends exactly the fields the agent deserializes (includingpost_install_command, which was nested in the wrong place before). This is a backend/gateway-only fix compatible with already-deployed agents. agent_commandRotation Steps Timed Out Against Every Agent — The step forwarded an HTTP request through a proxy message type the agent never implemented, so service restarts and other command steps waited 30 s and failed. The step now uses the agent'sagent_commandrequest (allowlist-enforced) and honorstimeout_seconds.- Agent File, WebLogic and Oracle Wallet Targets Could Not Execute —
agent_file_sync,agent_file_backupandweblogic_restartwere generated by the workflow builder but never registered (unknown step type), and the registeredweblogic_deploy/oracle_wallet_deploysteps returned executed without contacting any host. These targets now run through real, registered steps (see New Features); the folded-in step typesweblogic_restartandagent_file_backupare refused with a hint to rebuild the deployment target instead of reporting false success. - Web Server and Load Balancer Targets Were Skipped Silently — The workflow builder had no case for
web_serverandload_balancertargets, so a rotation with such a target reported success without deploying anything. They are now refused when saved and fail the workflow build with an explicit reason when already present (see Deployment Targets Are Validated When Saved). - Database Wallet Targets Could Be Created Without an Agent — The UI marked Database Wallet as not requiring an agent, while the deployment runs
orapkion the database host through the agent; such targets could never execute. The UI and the API now require an agent for this target type, and target updates sent as JSON documents are serialized explicitly on every database driver (GORM does not run field serializers for map-based updates; the Postgres driver happened to encode the struct, SQLite rejected it). - Windows
windows_rootTarget Imported a Private Key Into the Trusted Root Store — The Windows keystore installer built a PFX with the private key for every store and used the raw keystore type (windows_root) as the store path, which is not a valid Windows store name.windows_rootandwindows_catargets now install public certificates only (leaf into the designated store, chain classified intoRoot/CA),windows_myreceives the leaf + key PFX without the chain, and keystore types are mapped to the realMy/Root/CAstore names. The backend side matches this: theagent_keystore_syncstep no longer requires a private key forwindows_root/windows_ca(a CA certificate without a key can now be deployed to a trust store) and never includesprivate_key_pemin the bundle for those stores even when the export carries a key; JKS / PKCS#12 /windows_mystill fail fast without a key. The UI valueWindows Cert Store(keystore_type: windows) never matched anything the agent accepts; the editor now offers Windows — Personal (My), Trusted Root CAs and Intermediate CAs explicitly (no path, alias or store password for Windows stores), saved targets with the legacywindowsvalue are canonicalized towindows_myat execution time, andagent_keystoretargets are validated at save (JKS / PKCS#12 needkeystore_path; unknown store types are refused). - Legacy Records Could Export the Wrong Certificate as the Leaf — Certificates imported before
leaf_certificate_pemexisted keepraw_certificate_pemexactly as uploaded, which may be a "root, leaf" bundle; the new chain resolver initially read that raw field before the leaf-firstpublic_chain_pem, so such a record would have exported, displayed and deployed the CA certificate as the leaf (and reported an empty, complete chain). The leaf is now selected by the record's stored SHA-256 thumbprint wherever it sits in the stored material; without a thumbprint the pre-existing order (dedicated leaf field → first block ofpublic_chain_pem→ raw upload → DER) applies. Covered by a regression test with root-first raw bundles for both end-entity and CA records. - Discovery Merged Multiple End-Entity Certificates From One File — The agent reports one record per end-entity certificate found in a PEM file but sends the whole file as the body; the backend normalized the bundle with a "first non-CA block" heuristic, so a file holding two end-entity certificates (old + renewed, server + client) collapsed both reports into the first certificate and the second was never recorded. The reported fingerprint now selects the leaf inside the bundle, sibling end-entity certificates are excluded from that leaf's chain, and the heuristic is used only when no block matches.
- Windows Personal Store Deployment Needed a Keystore Password That Does Not Exist — The Windows
Mystore has no keystore password; the agent only needs one to wrap the temporary PFX it imports and deletes on the host, and PowerShell refuses an empty value. Targets of typewindows_mywithout a configured password therefore failed at install time. Theagent_keystore_syncstep now generates a one-time random PFX password when none is configured (it is never logged or persisted, and an operator-provided password is still honored), so no meaningless secret has to be provisioned for Windows stores. On the agent, the PFX password is handed to PowerShell through the process environment instead of being interpolated into the script, so a password containing quotes or$can neither break the import nor be echoed back in an error. When the deployment runs through a gateway, the one-time password is derived from the step's idempotency key, so a retried attempt presents the identical bundle and the agent replays the completed install instead of rejecting it as a different operation. Windows store names are resolved by one shared rule on the agent:Myand any plain LocalMachine store name discovered or configured on the host (for exampleWebHosting, the IIS default on current Windows Server) are identity stores that receive the PFX;Root,CA,AuthRoot,TrustedPublisherandDisallowedare trust-anchor stores that receive public certificates only — a private key is never imported into them, including through the renewal and legacy metadata paths; a bundle that carries a private key for a trust-anchor store is refused with an explicit error instead of being installed half-way (the renewed key would otherwise be lost silently). Names that could alter a PowerShell script are refused. Works with already-deployed agents (the backend change alone fixes the install). - Inventory Issuer Candidates Were Not Identified by Thumbprint — The chain resolver's issuer lookup did not load
thumbprint_sha256for candidate CA records, so the thumbprint-based leaf selection introduced above did not apply to them and a legacy intermediate stored root-first was never offered as an issuer (the chain stayed incomplete — safe, but the completion did not happen). The column is now loaded and a regression test covers a root-first intermediate candidate. - Private Key Import Accepted Any Key for a Certificate Without a Body —
POST /discovered-certificates/{id}/import-keyskipped the key/certificate match when the managed certificate had no stored body (the shape every adoption produced before this release), so a mismatched key could be stored silently and only fail at deployment. The import now rejects such a request with an explicit error until the body is present. - Attaching a Key to a Body-less Managed Certificate Left It Without a Body — The import update path attached the key but did not store the leaf PEM / DER on records that had none; it now attaches the body, keeps a richer stored chain, and completes a missing chain from the inventory.
- Certificate Import Took Identity From the First PEM Block — Bundles ordered
root, intermediate, leaf(as emitted by some tooling) were recorded with the root's common name, serial and thumbprint while the stored body was the leaf. Identity and metadata now derive from the normalized leaf regardless of block order. - Multi-File Certificate Import Dropped Separate Key Files — Uploading a certificate file together with a separate
.keyfile silently discarded the key (the UI claimed it had been paired during preview) and imported the certificate alone, so re-importing a managed certificate to add its key always failed with "already exists". The key is now paired on the backend and imported with its certificate. - Secret Rotation No Longer Fails on the Backup Foreign Key — Every secret rotation aborted in the background saga with
insert or update on table "rotation_backups" violates foreign key constraint "rotation_backups_execution_id_fkey". The pre-rotation backup was created before the rotation execution row existed and never setexecution_id, so the non-null foreign key rejected the insert and no rotation could complete. The backup is now created inside the execution (after the runtime probe, before the first mutating step) with a validexecution_id, and organization resolution is validated up front. The regression was invisible because the SQLite test harness does not enforce foreign keys and the constraint exists only in the SQL migration; a foreign-key-enforced regression test now covers the real insert path. - Rotation Template Migrations Handle the New Policy Fields Correctly — The rotation template persistence path and its migrations were corrected so the newly added policy fields (
lead_time_days,grace_period_days,secret_custody_mode) round-trip consistently between the API, SDK, provider, and the stored catalog. - Rotation Template Update No Longer Panics on Partial Edits — The rotation template create/update request decoder dereferenced typed-nil pointers, so any request that omitted an optional field — the common case for a single-field edit such as changing only the interval — panicked and returned HTTP 500. The decoder is now presence-aware: omitted fields are skipped, an explicit
0orfalseis preserved as an intentional value, andproject_idcan be set, changed, or cleared (with an explicitnull) without affecting other fields. - Retired Agents Can Re-Enroll With an Authorized Replacement Token — Re-registration for an unregistered or revoked agent was rejected outright, so a replaced host could not come back even with the single-use token issued by
reregister. Re-enrollment of a retired agent is now allowed only with a purpose-issued replacement token — distinguished by a newpurposediscriminator on deployment tokens — while stale deployment tokens and recovery tokens still cannot resurrect it; on success the agent's retirement markers are cleared and the single-use token is consumed. - Remote Uninstall Fails Cleanly and Reports Runner Startup Failures — Remote uninstall now rejects a host with no supported package manager (
apt-get/rpm) up front as unsupported, instead of reporting success after best-effort cleanup while the package remained installed. If the detached uninstall runner fails to spawn, the agent now reports that terminal failure back over the health channel — reconciling the already-accepted operation — instead of only logging it locally. - Keytab Rotation Fails Closed on Agent-Status Lookup Errors — A database error while checking a keytab deployment target's agent status is no longer treated as "inactive" (which silently skipped the deploy while still reporting the rotation completed). The rotation now fails closed on a lookup error and only skips a confirmed-inactive agent.
- Rotation Backup Acknowledge Restricted to the Recovery-Required State —
POST /rotation/backups/{id}/acknowledgenow transitions only a backup that is actually inrecovery_requiredstate, returning404for an unknown id and409for any other lifecycle state, instead of silently mutating a backup in any state. - Terraform
mazevault_deploymentImport Restores the Organization — The deployment resourceReadnow repopulatesorganization_idfrom the server, so an imported deployment can be destroyed; previously the delete call sent an empty organization and was rejected with400. - Helm Customer Chart Uses Redis Instead of Silently Falling Back to Memory — The customer Helm chart defaulted
externalRedis.connectionQuerytoabortConnect=false, a StackExchange.Redis (.NET) option that the Go backend's Redis client rejects (redis: unexpected option), so the backend fell back to the in-memory cache, gateway state could not use Redis, and the OCSP responder crash-looped on startup. The default is now empty, and the chart now refuses to render whenconnectionQuerycontainsabortConnect— customers who set it in their own values must remove it. The backend and OCSP responder also no longer log the Redis password when a Redis URL fails to parse or connect: URLs in connection errors are redacted and URL parse errors no longer echo the raw URL. - Certificate Note Rejected Below the Displayed 256-Character Limit — Saving a certificate Note failed for text well under the advertised 256 characters whenever it contained non-ASCII characters (for example Czech diacritics), and the detail view gave no feedback at all. The backend enforced the limit in UTF-8 bytes while the UI counter, the request validator, and the
VARCHAR(256)column all count characters, so a 2-byte character such asřconsumed two units of the quota (≈240 characters was the effective ceiling for typical Czech text). The same byte-based check affected certificate tags (64) and the documentation URL (500). All three limits are now enforced in Unicode characters on every layer, the Note editor counts and truncates by code points (an emoji counts as one character), and the full 256 characters can be saved regardless of script. In addition, the Tags / Documentation / Note section no longer swallows API errors: validation and permission failures are shown inline next to the field, the editor keeps the draft open for correction, and in-flight saves cannot be submitted twice. Certificate import now applies the same tag normalization (trim, de-duplicate, 64-character / 50-tag limits) as the detail editor. ThePUT /certificates/{id}request body (UpdateCertificateRequest) is now described in the OpenAPI specification. No schema change is required. - Managed Tokens Could Not Be Saved in Orchestrator Mode With Azure Key Vault — Creating or renewing a managed token (
POST /tokens,POST /tokens/{id}/renew) in Orchestrator Mode failed with500 failed to offload token value to external providerwhenever the offload target was Azure Key Vault. The generic key-offload path named every value it had no certificate metadata formazevault-keys/key-<unix-timestamp>— a path-style identifier designed for HashiCorp Vault that Key Vault rejects because secret names may only contain[0-9a-zA-Z-](400 BadParameter: Method PUT does not allow operation 'key-…'). The same identifier was used for keytabs and for private keys imported through discovery (mazevault-keys/<cn>-<serial>, with dots from the CN), so those offloads failed on Azure as well. The identifier is now generated per provider: Key Vault receives a flat, readable, collision-free name (mazevault-token-<token-name>-<id>,mazevault-keytab-<principal>-<id>,mazevault-<cn>-<serial>) that is validated against the Key Vault contract before any request is sent, while HashiCorp Vault and AWS Secrets Manager keep the historicalmazevault-keys/…layout unchanged. The token value itself is never altered — it is base64-encoded for transport exactly as before and round-trips byte-for-byte (covered by a test with shell metacharacters, whitespace and Unicode). Key Vault's hard per-secret limit (25 600 bytes of the encoded payload, ≈19 200 raw bytes) is now checked up front and reported as a400with the exact limit and the size of the submitted value, instead of a generic500from Azure; an explicit secret name that violates the Key Vault pattern is also refused as a400rather than being rewritten silently. Several latent defects in the same path were fixed together: the token service passed the tenant under the wrong metadata key (org_idinstead oforganization_id), so the offload integration was chosen system-wide — the first enabled secret-manager integration of any organization — and token reveal / delete resolved the integration without any tenant scope; integration lookup is now scoped project → organization and never widens to another tenant's vault (an explicitly selectedintegration_idthat is missing or disabled is rejected instead of being replaced); token renewal deleted the previous external value before the new one was written, so a failed offload left the token without any value — the order is now write → persist → retire, a renewal that fails leaves the previous value intact, and a metadata insert that fails removes the value it had just offloaded; a stored Azure reference carrying a version segment would have created a new secret named after the version GUID on update — the bare secret name is now extracted correctly; the asynchronous secret-offload worker queried a non-existentis_activecolumn onproject_integrations(enabledis the real flag); key-custody events for tokens and keytabs now reference the owning record, key type and acting user instead of a random UUID; and a certificate serial shorter than eight characters no longer panics the name generator. No database migration, API or configuration change is required. - Windows Agent Installed From the Generated Script Failed to Run as a Service — The install script ended with an unknown
installcommand and the agent could not run as a Windows service. The agent now runs as the serviceMazeVaultAgent(automatic start, automatic restart on failure) fromC:\Program Files\MazeVault Agent\, with data and logs kept inC:\ProgramData\MazeVault\; the agent gained theinstallanduninstallsubcommands. Re-running the script upgrades in place and migrates the earlier layout; it refuses on a host with the MSI package.C:\ProgramData\MazeVault\(bootstrap token, agent private key, pre-seed file) is now readable only by SYSTEM and Administrators; earlier installs left it readable by every local user, so re-run the script on existing Windows hosts. - MongoDB Credential Check Accepted Any Password With a Connection URI — For a MongoDB integration configured with a connection URI, verifying a rotated user's credentials authenticated with the user from the URI (usually the admin) instead of the rotated user, so a wrong new password passed and an old one was never rejected. The check now authenticates as the rotated user against the configured auth database (default
admin), keeping the URI's hosts and options. Host/port connections also failed to connect at all (must have a / before the query ?); the built URI is fixed. - Oracle Credential Check Accepted Any Password With a Connection String — The same defect affected Oracle integrations configured with
connection_string: the credential check connected as the user in the connection string instead of the rotated user. It now replaces the connection string's user and password with the rotated user's and keeps the rest of the string. - MSSQL Credential Check Ignored the Rotated User in Windows and Azure AD Modes — With
auth_modewindows, verifying a rotated user's credentials signed in with the backend's own Windows identity and ignored the user and password; withazure_adit tried an Azure AD sign-in for a database user that has a password, so a correct password could be rejected. The check now always uses SQL authentication with the rotated user, which is how rotated users are created; the admin connection keeps its configured mode. - CLI Exited 0 on Errors and Ignored
--profileand--config— Everymazevaultcommand printed its error and still exited with code 0, so scripts and CI could not detect a failed call (for examplemazevault secrets getagainst a server answering 500). Commands now exit with code 1 on any error: missing or unknown flags and commands (message on stdout, as before) and failed API calls, configuration or keychain errors (Error: …on stderr).--profile/-pwas never read, so the CLI always talked to the server ofcurrent_profile; it now selects the profile's server and its stored tokens for that run.--config/-cwas overridden by~/.mazevault/config.yaml; the given file is now read (as YAML). Check scripts before upgrading: a--profilethat is not in the configuration now fails with exit code 1 (profile '<name>' not found) instead of silently usingcurrent_profile, and a--configfile that does not exist fails instead of falling back to the defaults. Stored login tokens are now bound to the server that issued them and are never sent to another server (before,--configwith a profile of the same name pointing elsewhere sent that server the token); tokens stored by an older CLI do not record their server, so runmazevault auth loginonce after upgrading. - CLI
secrets get,listanddelete, wrong password and expired sessions —mazevault secrets get,secrets listandsecrets deletecalled routes the server does not have and never worked.getnow reads the secret fromGET /api/v1/secrets?project_id&key&environment,listfromGET /api/v1/projects/{id}/secrets?environment=…, anddeletefinds the secret's id in that list (exact key and environment; no match or several matches delete nothing) and callsDELETE /api/v1/secrets/{id}. The JSON/YAML output ofsecrets listnames the change timeupdated_at(waslast_modified). A wrong password onmazevault auth login(also LDAP) now reportslogin failed: 401 Unauthorizedinstead ofunauthorized: please login again. When the stored refresh token had expired, the CLI crashed with a stack overflow; it now stops withsession expired, please login again. A refreshed session stores the new expiry and a rotated refresh token; a login or refresh response withoutexpires_inno longer marks the token as already expired. The CLI still cannot refresh a session (the server reads the refresh token only from its cookie), so log in again when the session expires. - OCI Vault Integration Could Not Create Secrets and Listed Deleted Ones — Creating a secret in OCI Vault (for example from a sync rule) always failed, because the request did not name the master encryption key that OCI requires. The OCI Vault integration config now has
key_id, the OCID of the vault's master encryption key; set it on every OCI Vault integration that should create secrets (without it, creating a secret fails with a clear error and nothing is sent to OCI). Reading, listing, updating and deleting secrets do not need it. Listing and name lookup now return onlyACTIVEsecrets, so a secret deleted through MazeVault (30 days inPENDING_DELETIONin OCI) no longer appears in the list or the external-secret import, and a name resolves to the active secret rather than a deleted one with the same name. - Database reconcilers: MongoDB session drain, PostgreSQL passwords, Azure SQL sign-in and MSSQL options — Draining the sessions of one MongoDB user ended every operation in the cluster, of all users; it now ends only operations run as that user in its auth database (
auth_database, defaultadmin). The PostgreSQL reconciler could not connect when the user name or password contained URL characters such as#,/or?; every value is now URL-encoded. The MSSQL reconciler signed in to Azure SQL withauth_mode: azure_adas a SQL login and failed; it now uses Microsoft Entra authentication: with a token (service principal, managed identity,DefaultAzureCredential; withuse_msiaclient_idnow selects a user-assigned managed identity, before the system-assigned one was always used) and, in password mode, through the public client application inclient_id, which that mode now requires. The MSSQL optionkeep_alive: trueprevented every connection;keep_aliveis now the keep-alive period in seconds (truekeeps the driver default of 30 s), andconnection_timeout,login_timeout(used whenconnection_timeoutis not set) andkeep_alivesaved from the web interface are no longer ignored.keep_alive_intervalhas no effect. - PostgreSQL database rotation rolls back and reconciles correctly — A failed rotation of a PostgreSQL integration configured with host, port and database (the form the UI creates) now restores the previous password; the rollback used to connect only through a connection string. Rolling back a
sqluser:<role>:<user>rotation (PostgreSQL and Oracle) restores the password of that user instead of the integration'susername; rolling backensurechanges no password and reports that role changes must be reverted manually, and a missing host is an error instead of a connection to localhost. Theensureoperation drops an undesired role that the integration admin created (PostgreSQL 16+ records the creator as a member, so such roles were kept), and malformeddesired_json,undesired_json,grants_jsonoraad_members_jsonis rejected withinvalid <field>by the PostgreSQL, Oracle and MongoDB connectors (as MSSQL already did) instead of reportingreconciledwithout doing anything. - PKCS#11 HSM devices stay usable after re-instantiation and list their keys — A second PKCS#11 HSM device on the same module, or the same device after an edit, a failed health probe or the 5-minute provider refresh, failed with
CKR_CRYPTOKI_ALREADY_INITIALIZEDand stayed unreachable until the backend restarted; the same happened to a CA configured for a PKCS#11 HSM after its first use. The module is now initialized once per backend process and shared, and a replaced device provider closes its HSM session. A CA on a PKCS#11 HSM keeps one HSM session while its HSM configuration is unchanged (before, issuance, renewal and scheduled runs opened a new session each time and never closed it). While a device is logged in to a token, another device on that token is accepted only with the same PIN: a wrong or missing PIN reports the device unreachable, and a changed PIN takes effect once all sessions on the token are closed (for example after a backend restart). Concurrent operations on one PKCS#11 device no longer crash the backend. The device key list and key details now read the key size from the modulus, so keys on a standard token (e.g. SoftHSM2) are listed instead of being skipped. - Azure Key Vault watch reports new secret versions — Watching an Azure Key Vault integration for external changes reported only created and deleted secrets; a new version of an existing secret (a value changed directly in Key Vault) was never reported, so no drift warning was raised. The watcher now uses the last-updated time from the secret list and, only for a changed secret, lists its versions (no values are read, the
listpermission is enough) and reports the update when the current version changed; a tag-only edit is not reported. A key reference that is not a secret id of the configured vault is now rejected. An end-to-end-encrypted value that cannot be decrypted is now an error instead of being returned as the encrypted envelope, and the remote identifier recorded for certificate and post-rotation syncs to Key Vault no longer contains a double slash whenvault_urlends with/. - Integration wizard lists agents, applies organization defaults and shows backend errors — In the integration wizard, "Key Vault is behind Private Endpoint" now lists the project's agents (it called an endpoint that does not exist and showed "Failed to load agents") and lets you pick an
activeagent (only the non-existent statusonlinewas selectable before). The database step applies the organization's security defaults only after the organization environments are loaded, so an environment such asprodmarked as production gets the production defaults. Errors from saving an integration, testing a connection, previewing Entra applications or saving a secret deployment target show the message returned by the backend instead of "Request failed with status code 400". - Agent discovery finds new certificates on every scan and shares its password cache safely — After its first filesystem scan the agent treated the scanned roots as done and skipped them in every later hourly scan until it was restarted, so certificates added in the meantime were never discovered; every scan now walks all roots again. A scan interrupted by a kill or crash still resumes after the restart; a cancelled scan starts its walk again, keeping its per-file progress (unchanged files are not parsed again). Keystore passwords approved in MazeVault and those found during a scan are now kept in a cache that is safe for concurrent use, so an approved password arriving while a scan or a renewal reads the cache no longer crashes the agent with
concurrent map writes. The search for password hints across the local disks now runs at most once per scan for the filesystem and the JKS scanner instead of once per keystore, and the look-up of a matching private key next to a certificate skips files larger than 1 MiB. Akey_vault_secret_idread from a JSON file next to a keystore is now fetched only from anhttps://….vault.azure.netURL; the host's managed-identity token is never sent to any other host. - Agent-Local Certificate Renewal Installs Only a Matching Certificate, Renews Discovered PKCS#12 Keystores and Seals Its Pending State — A PKCS#12 renewal with
reuse_keynow completes; before, the key read from the keystore was mislabelled and the install always failed. The agent refuses an issued certificate that does not match the private key it prepared, so a wrong certificate no longer replaces a working file or keystore. A PKCS#12 or JKS keystore found by the file scanner (typefilesystemwithkeystore_type) is now offered for agent-local renewal by the backend and accepted by the agent. The pending renewal under<state_dir>/pending-renewals/is now encrypted with a key derived from the agent's mTLS key (client_key_file) instead of holding the private key and keystore password in clear; an agent without an mTLS key keeps the pending renewal in memory only, so after a restart between prepare and install the install answers "renewal operation not found or expired" and the renewal has to be started again. A pending file written in clear by an older agent is sealed again when it is first read, or, without an mTLS key, moved to memory and deleted. The renewal task payload is unchanged. - Entra sync conflicts can be listed and resolved —
GET /api/v1/entra/{integrationId}/sync-conflictsandPOST /api/v1/entra/sync-conflicts/{id}/resolvedid not work: every pending conflict was refused as already resolved (500). A conflict now resolves once. Resolving an unknown conflict answers404, and a conflict that is already resolved answers409, also when two resolves race. Theresolutionrequest values staylocal_wins,remote_winsandmanual. They are stored asuse_mazevault,use_entraanduse_merged. The conflict JSON now uses the stored fields:field_name,mazevault_value,entra_value,status(pending,resolved,ignored),resolution,resolved_valueandresolution_notes. It replacesfield,local_valueandremote_value. - Several zero-knowledge secrets per environment; deleted and archived secret names can be reused — Creating a second zero-knowledge (v2) secret in the same project and environment failed with a server error, and a secret name that had been deleted or archived could not be created again. Uniqueness now applies only to live secrets: one live secret per name, and one live zero-knowledge secret per blind index, in a project environment (database migration 000276). Restoring an archived secret whose name (or blind index) has since been used again now answers 409 Conflict and leaves it archived; archive or delete the newer secret first. The migration refuses to run if live secrets already share a name or blind index in one environment, and lists them; archive or delete the extra ones and restart. Rolling the migration back refuses while rows exist that the old index would reject (for example several zero-knowledge secrets in one environment).
- Switches that default to on keep an explicit off — Saving
falsefor a flag whose default is on used to storetrue: CA accountauto_renewandauto_discover(an SSLmarket account set to manual no longer places paid renewal orders), the template flags auto-archive, incident notifications and auto-renewal, project environmentexistsandcompare_enabled, rotation resource and rotation targetenabled(a target created disabled is no longer deployed to), and custody events of failed key actions (now counted as failures). Records written before the upgrade are not changed: review CA accounts you switched to manual earlier, because they may still have auto-renew on. - ECDH key exchange works, integrations backing secrets can be deleted, Entra promotions appear in rotation history — Migration 000274 creates the
session_keystable, which no migration created, so every key exchange failed; it also widensrotation_executions.config_typeto 50 characters, so promoting a staged Entra secondary to primary is now recorded in rotation history and reports (the 22-character type did not fit and the failure was ignored; the record is now written in the promotion transaction, so a failure rolls the promotion back). Migration 000275 recreates thesecrets.external_integration_idforeign key withON DELETE SET NULL: deleting an integration that secrets use as their source (typicallynames_onlysecrets in orchestrator mode) failed on the foreign key; it now succeeds, those secrets are reported as orphaned (and marked missing in orchestrator mode) and lose the reference. A reference to an integration that no longer exists (possible only where the foreign key was never created) is logged and set to NULL by the migration. - Vault and internal CA issue certificates within the template and CA validity — A Vault CA account without
mount_pathnow uses the defaultpkimount also for certificate status and listing (before, status checks went to a wrong path and reported certificates as revoked), and Vault signing uses the template's validity instead of the account'sdefault_ttl. The internal CA caps a certificate's validity at the CA's own expiry, refuses to sign once its own certificate has expired, rejects signing without a certificate template with an error instead of crashing, and returns the chain up to the root for a subordinate CA. Re-created Vault providers no longer leave token-renewal routines running. - Server TLS certificate: mismatched key pair is rejected, replacements are audited — Uploading a system certificate (
POST /api/v1/system/certificate) with a private key of another certificate, or with an unreadable certificate, now answers400instead of500, and every successful replacement writes the audit eventSYSTEM_CERTIFICATE_REPLACED(who, when, subject, serial and expiry; never the key). The self-signed certificate created during setup covers the host of the organization's web URL (before, the whole URL was put in the certificate and matched no host) and no longer erases the master key generated in the same bootstrap step. - Certificate exports are audited; template auto-archive runs; CA status sync uses the account settings — Every certificate export (
GET /api/v1/certificates/{id}/export, including exports with the private key) now writes the audit eventCERTIFICATE_EXPORTwith the user, format, whether the key was included and the result (failures included, also when the private key cannot be read or retrieved); the password and key are never recorded. Expired certificates are archived hourly when their template has "auto archive expired" set, after "archive after days" (the option had no effect before); each automatic archive writes the audit eventARCHIVE_CERTIFICATE, and restoring such a certificate makes it usable again. The periodic status sync with external CAs uses the CA account's settings (for example an SSLmarket sandbox or custom URL) instead of the provider's default endpoint. - Renewal cancel keeps finished renewals; PFX import keeps a single CA certificate; Cloudflare DCV cleanup reports failures —
POST /api/v1/renewal-queue/{id}/cancelno longer rewrites a completed renewal to cancelled (it answers409) and answers404for an unknown id instead of success. Repeating a renewal hand-off repair that already succeeded no longer fails. Importing a PFX through the OpenSSL fallback keeps the chain when it contains a single CA certificate (before, that certificate was dropped). Removing a DNS-01_acme-challengerecord from Cloudflare reports an error when Cloudflare refuses it (for example a token without DNS edit permission) instead of silently leaving the record behind. - Notification and monitoring providers report real delivery results — A Dynatrace event or metric rejected by the API (for example
401with an expired token) and an SMS rejected by SMSEagle (HTTP 200 with an error text such asInvalid login or password) are now errors in the log instead of counting as delivered. Microsoft Teams webhooks created through Power Automate Workflows answer202, which is now a successful delivery. Zabbix alerts were dropped and metrics were sent in thezabbix_senderformat over HTTP: both now go through the Zabbix API methodhistory.push(Zabbix 7.0 or newer) atZABBIX_URL(the frontend URL;/api_jsonrpc.phpis appended when missing), authenticated with an API token in the new variableZABBIX_TOKEN(keep it in the secret store); alerts go to the trapper itemmazevault.alert(type text) and metrics to trapper items named by their key, all on the hostZABBIX_HOSTNAME, so create those items (if an item restricts "Allowed hosts", include the Zabbix frontend's address). The unused mock webhook package is removed. - E-mail notifications are well-formed and the weekly report skips inactive channels — SMTP messages now carry the
FromandDateheaders (RFC 5322); some mail servers rejected or spam-filed messages without them. A subject is RFC 2047 encoded when it contains line breaks or non-ASCII characters, so a resource name such as a secret key or a discovered certificate's common name can no longer add headers (for exampleBcc) to an alert e-mail; an address containing a line break is refused. HTML e-mails (weekly report, share links) use correctMIME-Version/Content-Typeheaders. The weekly report is sent only to report-enabled channels whose integration is active. - Report exports: CSV cells cannot run as formulas, the Terraform export stays valid — A CSV export cell that starts with
=,+,-,@, a tab or a carriage return (for example a certificate common name=HYPERLINK(…)or a project name) now gets a leading', so Excel or LibreOffice shows it as text instead of evaluating it. The Terraform export of a project or organization gives a secret key that exists in several environments a separate resource per environment (db_password,db_password_prod) instead of a duplicate resource address, escapes quotes, backslashes, line breaks and${/%{in names, keys and environments, and turns any character other than letters, digits and_in a resource label into_. - Reconnecting agents stay connected; rescans keep the operator's decision on discovered config files — When an agent reconnected, closing its previous WebSocket removed the new connection as well, so the agent showed as not connected and certificate sync, secret sync and agent commands failed with
agent not connecteduntil it reconnected again. The old connection now leaves the new one alone. A configuration file that was ignored or adopted from config discovery no longer returns topending(and an adopted one no longer loses its link to the configuration file) when the agent scans it again. - Sync rules: updates are validated and schedules are honoured — Changing a sync rule's
target_environmentorsync_direction(PUT /api/v1/projects/sync-rules/{ruleId}) now applies the checks of creating one: a pull or bidirectional rule needs a target environment, a reserved or invalid environment is rejected with400, and the environment is stored in its canonical form. Scheduled syncs follow the rule'ssync_schedule(a cron expression such as*/5 * * * *or@daily); before, every enabled rule ran when it had not synced for an hour, whatever its schedule. A rule without a schedule, or with one that is not a valid cron expression (logged as a warning), still syncs hourly. - Configuration file versions no longer keep extracted secret values in the placeholder copy — When a discovered configuration file was adopted with secret extraction, the secrets were stored in the vault but the version's placeholder copy (the content with
${VAULT:…}references) still contained the values in clear (encrypted at rest like all version content). The placeholder copy now has the${VAULT:<name>}reference in place of each extracted value. Once after the upgrade, in the background after the server has started, the primary rewrites the placeholder copies of existing versions that still equal their original content (log lineconfig version placeholder copies regenerated; the run is recorded insystem_configurationsasconfig_version_placeholders_regenerated_atand not repeated). A copy that already has placeholders is never rebuilt. A version whose secret can no longer be read, or whose secret was rotated since, keeps its copy (logged asconfig version placeholder copy not regenerated). The original content of each version is unchanged. - Gateway registration establishes the E2EE session —
POST /api/v1/gateways/registernow also answerssession_idandserver_public_key(additive) when the gateway sent a valid P-256public_key: the gateway derives the session key from it, requests its mTLS certificate and encrypts its heartbeats from the first one. The primary stores the session key encrypted withMAZEVAULT_MASTER_KEY, so encrypted heartbeats still open after a backend restart and on every replica. Older gateways ignore the new fields. A gateway can now hold more than one session (each gets the next key version). Sessions are not renewed yet: 23 hours after registration the gateway sends its heartbeat unencrypted again, still with its API token.POST /api/v1/gateways/csrnow signs only a CSR for the session's own gateway (CNgateway-<id>, optionally the DNS namegateway-<id>.mazevault.local, no other SANs) and only while the gateway is active; any other CSR is refused with 403. - Azure Key Vault: external values, gateway sync links and certificate key usage — Reading a secret value that MazeVault stores in Azure Key Vault (key offload) returns it exactly as stored; a plain value that happened to be valid base64 (for example
password1234) was returned decoded. Secrets synced from Key Vault through a gateway are now linked to their integration like a direct sync, so they show as synced from the vault instead oflocal_only. A Key Vault certificate request run directly on the primary keeps the template's key usage (it was dropped and the vault issued its default key usage). The gateway task format is unchanged. - HSM devices: routing defaults and Azure Key Vault / SoftHSM key operations — An HSM device created without
environmentsorapplies_tonow serves every environment and scope, as documented (it was never selected, sohsm_generatorrotations failed with "no HSM device configured"); existing devices are fixed without a migration. Azure Key Vault HSM devices create ECDSA keys on the curve of the requested size (P-256, P-384 or P-521; other sizes are refused, before every key was P-256), return the public key and RSA key size correctly, and keys listed by the device can be used by name. The built-in software HSM signs with RSA-PSS and restores RSA and EC keys it wrapped itself. - Kubernetes secret rotation step targets the configured cluster — When MazeVault runs inside Kubernetes, the
kubernetes_secretrotation step used MazeVault's own in-cluster credentials even when the step configured akubeconfig, so it wrote the secret into MazeVault's own cluster. The configuredkubeconfignow always wins; in-cluster credentials are used only without one. Check rotations with akubeconfigthat ran on an in-cluster installation: the secret in the target cluster was not updated. - Rotation inputs: Entra extended configuration and HSM delegated custody — An Entra credential whose extended rotation configuration is not valid JSON no longer makes its rotation preflight fail with HTTP 500: preflight reports
invalid_extended_rotation_config(manual review), and the credential is not rotated automatically until the configuration is fixed. Anhsm_generatorstep indelegatedcustody mode no longer passes an empty password to the following steps; a database or secret step after it now fails withnew_password not foundinstead of setting an empty password. - Client errors answer 4xx instead of 500 — Validation, not-found and state errors of the API no longer surface as
500: an unknown role in a role assignment, a weak password, an integration URL refused by the SSRF guard, an invalid environment, an EAB credential without a project, a CSR that is not PEM, an unknown report type and a malformed JSON body answer400; unknown ids (archived items, gateways, organization logos, Terraform export, secrets, provider schemas, a template of another organization) answer404; approving a request or renewal that is no longer pending, copying a secret onto an existing key and activating DR while the primary is active answer409; an invalid agent bootstrap token answers401. The response never contains database or constraint text. Revoking another user's API token answers404instead of204(nothing was revoked). Error bodies of these endpoints now use the common{code, message, request_id}shape. - Keytab rotation trigger and format conversion work —
POST /rotation/resources/keytab/{id}/triggerreaches the keytab executor instead of answering400.POST /format/convertconverts the certificate's public certificate and chain (requirescertificate:readon the certificate) instead of returning a placeholder. - SRP sign-in no longer reveals which accounts exist —
POST /auth/srp/initanswers an unknown email or an account without SRP like a real account (200with a stable salt); the verify step then fails with401as for a wrong password. Before, it answered404or400./auth/srp/initand/auth/srp/verifycarry the same rate limit as/login(429when exceeded). - Password length counts characters; LDAP sign-in reuses accounts regardless of e-mail case — The 8-character minimum and 128-character maximum of local passwords now count characters instead of bytes, so a 7-character password with accented letters is refused and a long one with accented letters is accepted. An LDAP sign-in whose directory returns the
mailattribute in mixed case (common with Active Directory) now signs in to the existing account instead of creating a second one; new LDAP accounts are stored with a lowercase e-mail. Licence region restrictions (allowed_regions) are not enforced while no GeoIP database is configured, instead of treating every public address as an unknown country. - Shared links: expired links are deleted, wrong passphrases are limited — Opening a shared link that has expired or used up its views now really deletes it (the delete was rolled back, so the encrypted value stayed in the database). A passphrase-protected link is burned after 5 wrong passphrases; until then each wrong passphrase answers
403as before, afterwards the link answers404even for the correct passphrase. The count is kept in the new columnshared_secrets.failed_attempts(migration 000298). - External-only secret values fail loudly; config extraction handles repeated keys — Reading a
names_onlysecret (value kept only in an external provider) when neither key offload nor a sync rule can resolve it, or reading any secret without a local value in Orchestrator Mode without a sync rule service, now fails with an error instead of returning an empty value. Extracting secrets from a configuration file that has the same key twice (for examplepasswordin two INI sections) now stores both values; the second gets the placeholder…/password_2instead of aborting the extraction. - Secret password history is salted and no longer returned by the API — The history used to refuse reusing one of the last 10 values now stores each value as a salted PBKDF2-SHA256 hash instead of a plain SHA-256, so equal values cannot be linked across secrets. The history is now actually stored with each value change (it was never saved, so the reuse check never refused anything); updating a secret to one of its last 10 values is refused with
400(PUT /api/v1/secrets/{id}, the Terraform provider and other user writes). Re-sending the current value is not a reuse: it is applied as a metadata-only change without a new version, so a Terraform metadata orttl_hourschange keeps working. System restores and syncs are never refused: compensation of a failed rotation, rollback from a rotation backup, sync pulls, sync conflict resolution, cross-project sync and the Key Vault pre-rotation sync. Existing entries keep working for the reuse check until newer values replace them. Secret responses no longer containpassword_history_hashes. - Licence client understands the licence server's answers — A heartbeat answered with a revoked or expired licence (plain
200withLICENSE_REVOKED/LICENSE_EXPIRED) now marks the backend licenceREVOKED/EXPIREDinstead of leaving itACTIVEand failing to decrypt. The hourly usage metrics are sent with a licence validation request (POST /api/v1/validate) instead of the non-existent/api/v1/metrics, which answered404for every organization. The licence server does not use these metrics yet, and the hourly requests count against its validation rate limit. Enrollment rejected by build authentication now logs the targeted hint (checkBUILD_AUTH_SECRET, or the system clock / NTP). - Archive restore of unknown items fails; audit retention can delete — Restoring a project, secret or certificate that does not exist now answers
404and writes noRESTORE_*audit event (it answered success and audited the restore). The audit retention purge can now really delete events older than the retention period (at least 1 day): the immutability trigger is lifted only inside the purge transaction, and a failed purge is logged instead of being ignored. No job runs the purge yet, so audit events are still kept indefinitely. - Default organization is the first one created — Features that use the default organization (and incidents of rotation resources without a project, such as platform system keys, including approval-continuation incidents) now use the organization created first. Before, it was whichever organization sorted first by its random id, so on an instance with several organizations another tenant could receive a platform key's rotation-failure incident and its notifications. A service identity without a single project now gets its incidents in its own organization. Check after upgrade (instances with several organizations): routes without a project judge organization-scoped roles in the default organization, which may now be a different organization than before; verify which administrators hold organization roles there. Agent bootstrap tokens (
POST /agents/bootstrap) now create the deployment in the organization theagent:adminpermission was checked in; for a global administrator without an organization context that is the default organization, and the request answers400only when no organization exists. Theagent-bootstrapserver command takes an optional--organization-id; without it the token goes to the default organization, which the command prints on stderr, and agent discovery returns theagent-mtlstemplate of the agent's own organization. - Agent-proxied integrations can be saved (check the migration log after upgrading) — Saving an integration that goes through an agent failed, because
project_integrations.agent_idpointed at users instead of agents. Migration 000272 retargets it to agents. Every existingagent_idthat matches no agent (it could only hold a user id) is set to NULL, so that integration has no agent bound until you set one, and each such row is logged as aNOTICEin the migration log. After upgrading, check the migration log for these notices and re-bind the listed integrations to their agents. - Microsoft Graph: A Wrong Client Secret Was Sometimes Retried — The retry layer of the Entra ID (Microsoft Graph) client looked for an HTTP status anywhere in the error text, so a random trace or correlation ID containing e.g.
a503made aninvalid_client(wrong secret) answer look retryable and the token request was sent again. A status number is now recognised only as a whole word; a wrong secret fails after one token request. - Terraform:
mazevault_shared_secretshares a secret by its ID; Go SDKCreateSharedSecretrequiresValue— Creating the resource always failed with400because the backend needs the value to share. The provider now reads the value of the secret named bysecret_idwhen the share is created and sends it; the value is never written to Terraform state, andshare_urlstays sensitive. A secret whose value the server cannot read (zero-knowledge, names-only or external) fails with a clear error instead of sharing nothing. In the Go SDK,CreateSharedSecretreturns an error before any request whenValueis empty;SecretIDstays deprecated and the caller passes the value.
Security & Dependency Updates¶
- API tokens of a deleted user stop working — Deleting a user (it moves to the Archive) now switches off the user's API tokens (
mvt_…), and a token of an archived user is refused even while still marked active. Before, such a token kept authenticating with every role the user had when deleted, until it expired. Restoring the user from the Archive does not switch the tokens back on; the user creates new ones. Tokens of users archived before this release are refused too, without any action. - Rotation and sync steps stay inside the rotated resource's project — Before each rotation step and post-rotation action runs (also when a rotation is resumed, delegated to a gateway or runs an Entra post-rotation delivery), MazeVault checks that every integration it names belongs to the project of the rotated secret, certificate or Entra application, that an
agent_idis an agent of its organization and that atarget_project_idis a project of its organization, and that a secret (secret_id,password_secret_id), certificate (certificate_id) or Entra credential (credential_id, by its application's project) the step reads or writes belongs to the same project and anorg_idis its organization; otherwise the step does not run and the rotation fails (a post-rotation action is recorded as failed). A sync rule whose integration is in another project now fails instead of running, rotation preflight reports another project's integration as missing, and a secret link to another project's integration is left out of the generated rotation workflow. The API already refused integrations, anagent_idor atarget_project_idoutside the scope on save;secret_id,password_secret_id,certificate_id,credential_idandorg_idare not checked on save and are refused when the step runs. This covers hand-written workflows and configurations saved by older releases. Certificates without a project and Entra deliveries started before the upgrade are not narrowed. Managed token deployment targets likewise accept only an integration, agent ortarget_project_idof the token's organization (otherwisePOST /api/v1/tokens/{id}/targetsanswers 400), and an existing target outside it fails on the next sync instead of receiving the token. - Audit log and archive stay inside the organization —
GET /api/v1/audit-logs/andPOST /api/v1/audit-logs/search(also the aggregations) now list only events of the projects and organizations where the caller holdsaudit:read; before, anyaudit:readholder saw every organization's events. Audit events get an organization (migration000237: columnaudit_events.organization_id, filled on write from the event's project or the resource it names, existing events backfilled); events that belong to no organization (sign-ins, user accounts, system keys) are listed only to a global role. The archive (/api/v1/archived/*, the Archived Items page) likewise lists only the caller's projects, secrets, certificates, discovered certificates and certificate requests; deleted users have no organization and are listed only to a global role. Restoring or permanently deleting an archived item (/projects|secrets|certificates/{id}/restore|permanent,/archived/…/{id}/restore|permanent) is now checked in the item's own organization (403 for another organization's item, 404 for an unknown id); deleted users can be restored or deleted only by a global role. Log streams (Splunk, Elasticsearch, Syslog) now receive only the events of the organization that configured them; before, every organization's stream received every organization's audit events. - Log streams: security events without an organization reach the organizations of their user (BREAKING for installations with several organizations) — Events that belong to no organization (sign-ins, MFA, password and user changes, role assignments, break-glass and temporary access) are streamed to the log streams of every organization in which the user the event is about holds an unexpired role, on the organization or on one of its projects. That user is the subject the event names (the signed-in user, the user whose MFA, password, roles or access changed, the break-glass target), never the user who performed the action; a user with roles in two organizations therefore appears in the Splunk, Elasticsearch or Syslog of both. With exactly one organization every log stream still receives every such event. With several organizations an event whose subject is not a user with an organization role (a failed sign-in with an unknown user name, changes to users who hold only global roles, removal of a role assignment, API token creation and revocation, instance settings, scheduled system jobs) is streamed to no destination; read these in the audit log (
/api/v1/audit-logs, global role) if your SOC relies on them. - Agent enrollment needs an organization internal CA or an instance CA (BREAKING) — Agent mTLS certificates are no longer signed by another organization's internal CA: agent enrollment fails until the organization initializes its internal CA (Organization Settings → Project Settings → Certificate Authorities → Initialize Internal CA) or a global administrator creates an instance CA (
POST /api/v1/ca/initialize). Check this before upgrading if agents enroll in an organization without its own internal CA (see Certificate Authorities, CA Accounts and Templates Stay in Their Organization). POST /api/v1/ca/initializeneeds a global role (BREAKING) — Creating an instance CA now requires a global role; an organization role gets 403. Automation that creates it with an organization-scoped token must use a global one.- Weekly-report recipients are set per organization (BREAKING, check after upgrade) — Each organization now has its own weekly-report e-mail recipients, and they receive only that organization's report. An organization admin (
report:read/report:writein the organization) reads and changes them withGET/PUT /api/v1/organizations/{id}/reports/settings, sends the organization's report withPOST /api/v1/organizations/{id}/reports/triggerand previews it withGET /api/v1/organizations/{id}/reports/preview; a global admin can do this for any organization, and a project role gets 403. Changing them is audited (REPORT_RECIPIENTS_UPDATED). System Outputs → Weekly Expiry Report edits the recipients of the selected organization. The Monday run sends every organization its own report, and report-enabled channels now get it also when the organization has no e-mail recipients. Upgrade: on an instance with one organization, the existing recipients move to it automatically. With several organizations they stay as instance-level recipients that receive nothing (no organization's report goes to them) until a global admin adds them to the right organizations; the Weekly Expiry Report tab lists them for a global admin and clears them.GET/PUT /api/v1/reports/settings(global role) now read and change only that leftover list, andPOST /api/v1/reports/trigger(global role) sends every organization its own report. Expiring certificates without a project, which the instance-wide e-mail listed as unassigned, now appear in no organization's report: assign them to a project. - Orchestrator Mode: key offload without a project is refused (BREAKING) — Importing or discovering the private key of a certificate without a project, and exporting, deleting or reusing at renewal such a key, now fails until the certificate is assigned to a project (see Offloaded Keys Stay in the Caller's Organization and Vault).
- Project Roles, Incidents, Terraform Organization Export and Agent Password Requests Stay in Their Organization — A project role (as the project's Access Management tab assigns it) no longer acts with the rights of the instance's default organization on routes without a project (managed tokens and keytabs lists, downloads and changes, certificate templates, CSR approval, the renewal queue and incident lists, creating service identities) when its project belongs to another organization; such a caller gets 403 there and passes
project_idof its project where the route takes it. Routes that take the project only in the request body (POST /api/v1/secrets/,POST /api/v2/secrets,POST /api/v2/secrets/compareand/migrate,POST /api/v1/certificates/csr,POST /api/v1/certificates/import,/import/bulk,/import/fileand the import previews) are judged in that body project (for/migratein each secret's), so project roles of every organization keep using them, and organization roles of an organization other than the default one, which were refused there before, can now use them too; an import without a project is still judged in the default organization.GET /api/v1/incidents/{id}andPOST /api/v1/incidents/{id}/resolveare judged in the incident's project or organization: another organization's incident answers 403, an unknown id 404.GET /api/v1/terraform/export/organization/{id}needsorg:readin that organization (403 otherwise, 400 for a malformed id)./api/v1/admin/password-requestslists only the requests of agents of the organizations in which the caller holdsagent:admin(a project role lists none, an agent without an organization needs a global role), and/approveand/rejectof another organization's request answer 403 (unknown id 404) and change nothing. - Project roles act only inside their project on keytab, token, CSR, renewal-queue and incident routes (BREAKING for API callers with project roles) — A project role now acts only on its own project's records also in its project's own organization; before, on routes without a project it had the rights of the whole organization there.
GET /api/v1/keytabs,GET /api/v1/tokens,GET /api/v1/renewal-queue/andGET /api/v1/incidents/list only the records of the projects and organizations in which the caller holds the read permission (a project role: its project's records, no organization-level ones; organization and global roles see what they saw before)./api/v1/keytabs/{id}(read, update, delete,download,history,check-compliance),/api/v1/tokens/{id}(read, update, delete,value,renew,targets) andPOST /api/v1/certificates/csr/{id}/approve,/rejectand/archiveare judged in the record's project or, without one, its organization: another project's or an organization-level record answers 403 and nothing changes, an unknown id 404.POST /api/v1/keytabsandPOST /api/v1/tokenswith aproject_idneed the permission in that project, which must belong to the organization the record is stored in; withoutproject_idthey need it at organization level.GET /api/v1/keytabs/dashboardwithoutproject_id,POST /api/v1/service-identities/andPOST /api/v1/certificate-templates/need the permission at organization level. API and SDK callers that hold only a project role get 403 on these creates withoutproject_idand see only their project's keytabs, tokens, renewal-queue items and incidents; the KeyTab and Token Management pages show such a user only its project's records, and importing a keytab or creating a token there (the forms send no project) needs an organization role. - Upgrade: plan a maintenance window for large audit logs — Migration
000237backfillsaudit_events.organization_idfor all existing events and holds anACCESS EXCLUSIVElock onaudit_eventswhile it runs. On large audit tables this takes minutes, during which audit writes (and the API requests that write audit events) wait and reading the audit log is blocked too; the backend does not finish starting until the migration is done, so raise the startup and liveness probe timeouts accordingly. The update rewrites every attributable row, so the table temporarily needs up to about twice its size in free disk space. Plan the upgrade in a maintenance window. - Gateways reach only their own tasks — The gateway task endpoints (
GET /api/v1/gateway/tasks,GET /api/v1/gateways/{id}/tasks,POST /api/v1/gateway/tasks/{id}/claim,PATCH /api/v1/gateway/tasks/{id}) now act only for the gateway authenticated byX-Gateway-IDand its token. Agateway_idin the query, path or body that names another gateway gets403, and a status update for another gateway's task gets404; before, a gateway with its own valid token could list (with decrypted payloads), claim and complete the tasks of every other gateway. Deployed gateways already send their own id in both places and keep working;gateway_idonGET /api/v1/gateway/tasksis now optional. - IIS and post-install commands can no longer be injected (agent and backend) — The agent's built-in post-install allowlist entry
Import-Module WebAdministrationnow matches only that exact command; previously anything appended to it (; …,&&,|) was executed on the agent host. The agent also refuses every post-install command that contains a line break (built-in andallowed_commandspatterns alike), because the shell runs each line as its own command, and on Windows agents every post-install command containing(,),{,},@,$, a backtick or any non-ASCII character, because PowerShell evaluates such expressions inside arguments before the program starts and treats Unicode spaces, curly quotes and dashes like their ASCII counterparts (structuredagent_commandrequests run without a shell and are not affected). On Windows, the agent also passes the certificate store, fingerprint and CA certificate names to PowerShell as environment values when it renews a certificate from the Windows store or checks the trust store, so a crafted store name or CA certificate name can no longer run code. The agent passes IIS application pool, site and host names to PowerShell as environment values instead of pasting them into the script, and logs a successful post-install command by program name only (wallet and keystore passwords no longer reach the agent log). The backend's IIS recycle step accepts only pool names made of letters, digits, spaces and. _ - ( ), so agents of earlier releases are protected too. Action required: a post-install command of the formImport-Module WebAdministration; Restart-WebAppPool …is now refused — useRestart-WebAppPool -Name "<pool>"alone (PowerShell loads the module automatically; the built-in pattern covers pool names of letters, digits,_,-and.), otherwise — e.g. for.NET v4.5 Classic— add a matchingallowed_commandspattern on the agent; a multi-line post-install command must be put on one line; an IIS recycle step whose pool name contains other characters fails validation and must be corrected. Agents and backends of the previous release stay compatible. - Connectors verify TLS by default (BREAKING, check before upgrading) — ADCS CA accounts now verify the server certificate unless Verify SSL was saved switched off (
verify_ssl: "false"); before, every ADCS connection, which carries the service account password, skipped verification for accounts created in the UI, even with the switch on. The PostgreSQL rotation step (postgres_db) withoutssl_modenow connects withsslmode=verify-fullinstead ofdisable, and also readssslmodeas the integration wizard stores it. Audit streams (syslog over TLS, Elasticsearch) now trust the PEM CA intls_ca_cert, so a private CA no longer needstls_skip_verify. Smallstep CA accounts with a Root CA Fingerprint and no trust bundle now trust step-ca's own root: MazeVault fetches/rootsonce and keeps only the root with that SHA-256 fingerprint, likestep ca bootstrap, soinsecure_skip_tlsis no longer needed. ADCS servers and PostgreSQL rotation targets whose certificate is not trusted by the backend stop connecting with anx509:error: add the CA to the backend's trust store (see TLS Configuration, section 8) or switch verification off explicitly. Smallstep CA accounts with a Root CA Fingerprint and no CA Trust Bundle whose step-ca sits behind a TLS-terminating proxy with a public certificate also stop connecting (the proxy's certificate does not chain to the pinned root): pass TLS through to step-ca, or put the proxy's CA into the CA Trust Bundle. - Secret values no longer stored in rotation workflows, step history or notifications — The default body of the
api_notificationrotation step (also used as an Entra post-rotation action) no longer contains secret values: the step context is redacted like thewebhookstep's, so a new client secret or password is not posted to the configured URL. Generated database rotation steps no longer store the integration's admin username and password in the rotation configuration and the step history; the orchestrator reads them from the database integration when the step runs. Migration000221removes the stored copies from existing rotation configurations and from the execution history wherever the referenced database integration still holds them (a step whose integration was deleted keeps its values; the migration reports their number as a WARNING in the PostgreSQL server log, andSELECT 'rotation_configs' AS source, id::text FROM rotation_configs WHERE workflow_steps::text LIKE '%"admin_password"%' UNION ALL SELECT 'rotation_execution_steps', id::text FROM rotation_execution_steps WHERE step_config::text LIKE '%"admin_password"%';lists the rows that still hold plaintext credentials). Previous Azure Key Vault values captured bypost_rotation_syncare no longer stored in the step output, and gateway task checkpoints of delegated rotations are encrypted at rest like the final result (checkpoints written by the previous release are still read). A downgrade does not restore the removed credentials; a pending database step of a rotation interrupted across a downgrade must be re-run as a new rotation. - Logout and password change revoke refresh tokens —
POST /api/v1/auth/logoutnow revokes the refresh token sent in therefresh_tokencookie on the server (and records theLOGOUTaudit event), so a copied refresh token no longer works after logout. Changing the password revokes every refresh token of the user; a browser session that changed it gets a newrefresh_tokencookie (API-token callers do not), other browsers and copied tokens must sign in again. A refresh token is no longer accepted as a Bearer access token (it was, for 7 days, even after logout); refresh tokens now carrytyp: refreshand a uniquejti, and every JWT without aroleclaim is rejected by the API. Access tokens already issued stay valid until they expire (15 minutes by default). - Organization integrations refuse internal targets (SSRF) — Creating, updating or testing a Jira, Teams, Slack or webhook integration now resolves the URL's host and is refused when any of its addresses is internal: loopback (incl.
::1and::ffff:127.0.0.1),0.0.0.0/::, private networks (10/8,172.16/12,192.168/16, IPv6fc00::/7), link-local (incl. the cloud metadata address169.254.169.254), carrier-grade NAT100.64.0.0/10and multicast. Previously only some IPv4 prefixes andlocalhostwere refused. On-premises installations whose Jira or webhook target resolves to a private address can no longer save or test that integration; integrations saved earlier keep sending until they are edited. Jira, Teams, Slack and webhook notifications no longer follow HTTP redirects: a target that answers3xxis reported as a failed delivery, so configure the final URL. - ACME Server Binds Every Request to the Signing Account (RFC 8555) — The built-in ACME server (
/api/acme/*) now serves an order, authorization, challenge, finalize or certificate download only to the account that created the order; another account gets404(previously any registered account could read another account's orders and finalize them with its own CSR).kidis the account URL from thenew-accountLocationheader, as RFC 8555 requires, so standard clients (cert-manager, certbot, acme.sh, lego) work after registration. The JWSurlheader is now required on every request, includingrevoke-certandkey-change, and must equal the URL listed in the directory, which is built fromMAZEVAULT_BASE_URL(set it to the external URL ACME clients use, otherwise requests fail with400 malformed). The EAB must be computed over the account key of thenew-accountrequest and carry thenew-accountURL; key rollover checks that the inner JWS has the outerurland names the signing account; revocation with the certificate's key (no account) requires the request to be signed by that certificate's key, and revocation in either mode requires the submitted certificate to be byte-identical to the issued one (a forged certificate with the same serial is404). The headeralgmust match the account key (ES256P-256,ES384P-384,RS256RSA), a JWS carrying bothjwkandkidis400 malformed, and an unsupported revocation reason code is400 badRevocationReasoninstead of being revoked asunspecified.ES384(P-384) account keys are accepted and verified with SHA-384, and a deactivated account gets401 unauthorizedinstead of404 accountDoesNotExist. - Entra ID SSO: Nonce Always Enforced, No More Linking by E-mail (action required) — The Entra ID sign-in now always rejects an ID token whose
noncedoes not match the one issued for that sign-in (OIDC replay protection); theMAZEVAULT_ENFORCE_OIDC_NONCEvariable is removed and ignored, delete it from.env/ Helm values (check-config.shreports it). An Entra sign-in is also no longer attached to an existing MazeVault account just because theemailorpreferred_usernameclaim matches: Microsoft documents both as mutable and unverified, so anyone able to set that address could take over the account, including the local administrator. An account is matched only by the immutable Entra object ID (oid) of the configured tenant: accounts that have signed in through Entra SSO before keep working unchanged. A user whose MazeVault account (same e-mail, in any letter case, including an archived account) has never signed in through Entra SSO now gets an error instead of a session; e-mail addresses of new Entra accounts are stored in lower case. One-time re-link: (1) an administrator deletes that MazeVault account (Access Control → Users), (2) permanently deletes it in the Archive (DELETE /api/v1/archived/users/{id}/permanent, permissionarchive:permanent_delete; this removes the user's API tokens and MFA records, anonymizes the account and writes an audit entry), (3) the user signs in through Entra ID, which creates a new account bound to their object ID, with roles from the Entra group mappings. A sign-in never removes an archived account itself. Roles granted locally to the old account and its personal data are not carried over, so re-grant them. Keep the local break-glass administrator on an e-mail address that is not used in Entra. - Database rotation steps: random Oracle passwords and no SQL injection (action required for Oracle) — An Oracle rotation step without
new_passwordin its input (simple rotation orsqluser:<role>:<user>) used to set the same fixed, publicly known password on every account; it now generates a 30-character random password (crypto/rand, at least two upper-case and lower-case letters, digits and^_~specials each, so it also passesora12c_strong_verify_function). Rotate such accounts again: affected are accounts rotated by an Oracle database step whose workflow did not passnew_password(for example a custom workflow without a password generator step); find them in the rotation history, or simply rotate every Oracle account managed by MazeVault. The MSSQL and Oracleensuresteps and the MSSQL, MySQL and Oracle reconcilers reject grant permissions that are not SQL Server permissions (whitelist) or Oracle/MySQL privilege keywords before any SQL is sent; Oracle steps reject invalid user, role and member names instead of creating an empty identifier. Session termination accepts only a session number (MSSQL, MySQL) orsid,serial#(Oracle), and the Oracle PDB name must be a plain identifier. The MySQL reconciler escapes passwords, user, role and grantee names and quotes schema/object names; the Oracle reconciler accepts passwords containing--or/*and rejects ones with a double quote. The generic SQL step no longer doubles backslashes for PostgreSQL (only when the server runs withstandard_conforming_strings=off), so passwords containing\keep working after rotation (a PostgreSQL account rotated earlier by this step with a\in its password, possible only with a custom password policy, has the doubled form stored and should be rotated again); the step stops with an error when the setting cannot be read, and it rejects user names with whitespace, quotes, brackets, backslashes or#. The MySQL reconciler builds its connection string with the driver, so a database name, user name or password containing?,&,@or/can no longer add driver parameters such asallowAllFiles. - Agent discovery requires the agent's client certificate —
POST /agent/discoverused to accept any signed-in user or token and handed out a fresh JWT of the agent registered for the given hostname (or created a new active agent). It now accepts only an enrolled, active agent identified by its mTLS client certificate (asPOST /api/v1/agents/me/refresh-tokendoes): the agent can update only its own name, OS and version, a differenthostnameis refused with403, a call without a valid agent certificate gets401, and the endpoint no longer creates agents (201is gone) — new agents enroll withPOST /api/v1/agents/register. MazeVault agents never called this endpoint, so deployed agents are not affected. - Gateway heartbeats change gateway identity only with the gateway's token —
POST /api/v1/gateways/{id}/heartbeatused to apply the role, environment, software version, managed identity client ID and supported environments from any caller who knew the gateway's ID; these fields steer task routing and failover. They are now applied only when the heartbeat carries the gateway's credentials from registration (X-Gateway-ID+Authorization: Bearer <token>orX-Gateway-Token). Heartbeats without them are still accepted and keep the gateway alive (last_heartbeat), so gateways of the previous release keep working, but their identity fields are ignored, logged and counted inmazevault_gateway_heartbeat_identity_ignored_total. Gateways of this release send the token, and a heartbeat sent as an E2EE envelope is now decrypted with the gateway's session key (its identity fields were previously never applied). Upgrade your gateways: a gateway still on the previous release no longer changes its role or environments through its heartbeat. - Organization settings, bootstrap completion and system health require authorization —
GET /api/v1/organization/summaryneedsorg:read; incident contacts follow the System Outputs page:GET /api/v1/organization/incident-contactsneedssystem_output:readandPUTneedssystem_output:write(before, any signed-in user could rewrite where incident notifications go). The endpoints act on the caller's organization, changing the contacts is audited (UPDATE_INCIDENT_CONTACTS), and withoutsystem_output:writethe page shows the contacts read-only.GET /api/v1/organization/settingsstays readable by every member. Completing the initial setup is nowPOST /api/v1/bootstrap/completeand needssystem:admin; it only takes effect once, later calls change nothing, andGETanswers405.GET /api/v1/health/system(component versions, connection pool, licence state) needs a signed-in user withsystem:read; liveness and readiness probes keep using the public/api/v1/health. The dashboard shows the Platform health panel only to users withsystem:read; for other users the sidebar shows the operational status as unavailable. - MFA codes and login challenges are single-use; disabling MFA re-authenticates — A TOTP code is accepted at most once (RFC 6238 §5.2; the last used time step is stored per user, migration
000224), and an MFA login challenge (session_tokenofPOST /auth/mfa/verify) issues tokens only once.DELETE /api/v1/auth/mfanow requires a JSON body with the accountpasswordor a current TOTP / recoverycode(400without either,401when it does not match), so an access or API token alone can no longer turn MFA off. API clients that call this endpoint must send the body.POST /auth/mfa/enrollandPOST /auth/mfa/verify-enrollmentanswer409while MFA is enabled, so the second factor can only be replaced after a re-authenticated disable. - Anonymous
POST /api/v1/enrollremoved — The backend answered an unauthenticatedPOST /api/v1/enrollfor any customer ID by creating a POC licence, a server node and an OAuth client withagent:read,agent:write,certificate:readandcertificate:requestscopes, and returned the client secret to the caller. Nothing in MazeVault used this endpoint: the backend obtains its licence from the licence server, and agents enroll with a bootstrap token (mazevault-agent enroll). The endpoint no longer exists; a call is now rejected. OAuth clients already created through it are deactivated automatically on upgrade (migration000225; nothing else ever created OAuth clients), and a token issued to a deactivated OAuth client is now rejected immediately instead of at its expiry. - Web Interface Security Headers (OWASP ZAP findings) — Every web interface response now carries
Referrer-Policy,Permissions-Policy,Cross-Origin-Opener-PolicyandCross-Origin-Resource-Policy, and static assets now also getX-Content-Type-Options: nosniff(nginx dropped it there). Static assets no longer sendAccess-Control-Allow-Origin: *. A Content Security Policy andCross-Origin-Embedder-Policy: require-corpship in report-only mode; enforcement follows once no violations are reported. Missing files such asfavicon.icoorsitemap.xmlreturn404instead of the application page, androbots.txtdisallows indexing. The deprecatedX-XSS-Protectionheader was removed. The headers are defined once in the frontend image and used by both the Docker Compose kit and the Helm chart. - Web Interface Security Headers (OWASP ZAP findings) — Every web interface response now carries
Referrer-Policy,Permissions-Policy,Cross-Origin-Opener-PolicyandCross-Origin-Resource-Policy, and static assets now also getX-Content-Type-Options: nosniff(nginx dropped it there). Static assets no longer sendAccess-Control-Allow-Origin: *. A same-origin Content Security Policy andCross-Origin-Embedder-Policy: require-corpare enforced. API responses carryCross-Origin-Resource-Policy: same-site, and nginx error pages no longer show the nginx version. Missing files such asfavicon.icoorsitemap.xmlreturn404instead of the application page, androbots.txtdisallows indexing. The deprecatedX-XSS-Protectionheader was removed. The headers are defined once in the frontend image and used by both the Docker Compose kit and the Helm chart. - Go Transitive CVEs Cleared (
x/net,x/mod) —golang.org/x/netwas upgraded0.55.0 → 0.56.0andgolang.org/x/mod0.37.0 → 0.40.0across theagent,cli,k8s-operator, andterraform-provider-mazevaultmodules to resolve CVE-2026-46600, CVE-2026-56864, and CVE-2026-56865. - Cross-Module Dependency Refresh — Additional module dependencies were updated:
golang.org/x/crypto → 0.55.0andgolang.org/x/sys → 0.47.0inocsp-responder,cloud.google.com/goand related packages inbackend, andgoogle.golang.org/grpc,google.golang.org/genproto, and OpenTelemetry packages interraform-provider-mazevault. - gRPC DoS Cleared (CVE-2026-84445) —
google.golang.org/grpcwas upgraded1.83.1 → 1.83.2inbackendandterraform-provider-mazevaultto resolve CVE-2026-84445 (gRPC-Go denial of service via malformed RPC requests), which was failing the dev-pipeline Trivy filesystem scan. The fix is pinned to the1.83.2patch line (the1.84.0line is still affected). A transitivegolang.org/x/mod → 0.40.0bump (CVE-2026-56864 / CVE-2026-56865) that a subsequent tooling update pulled back to0.39.0was re-applied. Verified withgo build,go vet,govulncheck(0 reachable), and a clean TrivyCRITICAL,HIGH --ignore-unfixedscan. - Jackson Core/Databind DoS Cleared (CVE-2026-68497, CVE-2026-89407, CVE-2026-89425, CVE-2026-91776, CVE-2026-91777) —
com.fasterxml.jackson.core:jackson-databindwas upgraded2.18.8 → 2.18.11in the Java SDK (sdks/java/pom.xml). The initial→ 2.18.10bump resolved CVE-2026-68497 (CPU DoS via unbounded numeric parsing); a subsequent Jackson advisory wave then flagged four more HIGH denial-of-service issues — two in transitivejackson-core(CVE-2026-89407 regex backtracking, CVE-2026-89425 unboundedStringBuildergrowth) and two injackson-databind(CVE-2026-91776 unbounded cache growth, CVE-2026-91777 quadratic forward-reference completion) — all fixed by2.18.11, which also transitively alignsjackson-core → 2.18.11. Everything stays on the2.18.xpatch line (drop-in, no API changes) and the dev-pipeline Trivy filesystem scan is green. The Java SDK now imports the Jackson BOM (com.fasterxml.jackson:jackson-bom, pinned via a singlejackson.versionproperty) independencyManagement, sojackson-core,jackson-databind, andjackson-annotationsstay version-aligned and future Jackson bumps are a one-line change. - x/net HTTP/2 DoS Cleared (CVE-2026-78669) —
golang.org/x/netwas upgraded→ 0.60.0acrossbackend,agent,cli,k8s-operator, andterraform-provider-mazevaultto resolve CVE-2026-78669 (net/http2denial of service via excessive HTTP/2SETTINGSframes), which was failing the dev-pipeline Trivy filesystem scan. All five modules build and test clean and the TrivyCRITICAL,HIGH --ignore-unfixedscan is green across every module. - Second Dependency Wave (verified) — A further batch of safe dependency bumps was applied and verified (backend
go build/vet/fullgo test, agent linux+windows build/test, frontendtsc -b/lint/build/165-test on Node 24, Trivy,govulncheck): backend Go (Azure azcore1.23.2 /azidentity1.14.1,azblob1.8.2,aws-sdk-go-v2/config1.33.8,service/s31.114.2,gin-contrib/cors1.7.9,go-ldap/ldap/v33.4.15,microsoft/go-mssqldb1.11.2,golang.org/x/crypto0.57.0,golang.org/x/oauth20.37.0,golang.org/x/time0.16.0,google.golang.org/api0.301.0 — the latter transitively advancedgoogle.golang.org/grpc → 1.84.0, which the current Trivy database no longer flags for CVE-2026-84445, and a coordinated lockstep bump ofk8s.io/api+k8s.io/apimachinery+k8s.io/client-go0.28.0 → 0.37.1, which the Kubernetes rotation steps compile and test clean against); frontend npm (lucide-react1.50.0,@types/node26.6.4,globals17.13.0,vitest5.0.3); and GitHub Actions (actions/checkout,actions/setup-go,actions/setup-nodev5 → v7, andactions/download-artifactv4 → v8, which stays compatible with the already-pinnedactions/upload-artifact@v7and the repository's name/pattern downloads). Deferred (blocked): the previously trackedtypescript7 andeslint10 PRs (still blocked by their respective ESLint peer ranges). - Consolidated Dependency Bumps — A large batch of routine dependency updates was applied and verified end to end (backend/agent
go test, frontendtsc/lint/build/165-test on Node 24, Trivy,govulncheck): backend Go modules (microsoftgraph/msgraph-sdk-go,swaggo/swag,swaggo/gin-swagger, Azureazcore/azblob,Venafi/vcert,aws-sdk-go-v2core/config/credentials/s3/route53,gin-contrib/cors,jackc/pgx,miekg/pkcs11,lib/pq,mongo-driver,prometheus/client_golang,stretchr/testify), agent Go modules (go-resty,prometheus/client_golang,golang.org/x/crypto0.57.0,golang.org/x/sys0.48.0,go-pkcs120.7.3), frontend npm packages (react/react-dom19.3.0,react-router8.4.0,axios1.20.0,date-fns,jspdf-autotable,@noble/hashes&@noble/ciphers2.4.0,lucide-react1.x,@types/node26,@testing-library/react&user-event,@vitejs/plugin-react6,globals17,autoprefixer,@tailwindcss/postcss,eslint-plugin-react-refresh,vite-plugin-node-polyfills), container base images (alpine3.21 → 3.24 for init-certs,python3.12-alpine → 3.14-alpine for the docs build stage), and GitHub Actions (actions/upload-artifact4 → 7,actions/github-script7 → 9,azure/aks-set-context4 → 5,azure/login2 → 3,codecov/codecov-action4 → 7,github/codeql-action3 → 4,docker/build-push-action6 → 7,docker/setup-buildx-action3 → 4,docker/login-action3 → 4,zaproxy/action-baseline0.14 → 0.15). Automated dependency PRs are now opened against thedevintegration branch (Dependabottarget-branch: devfor every ecosystem) instead of the default branch. Deferred (blocked upstream, kept as open tracked PRs):typescript7 (blocked bytypescript-eslintpeertypescript <6.1.0) andeslint10 /@eslint/js10 (blocked byeslint-plugin-reactpeer, which does not yet declareeslint ^10). - Material UI Upgraded to v9 (Major, Frontend) — The admin console was migrated from Material UI 7 to
@mui/material/@mui/icons-material9.4.0 and@mui/x-date-pickers9.14.0. All removed/renamed v9 APIs were migrated with the official MUI codemods plus targeted fixes: deprecated system style props (fontWeight,display,fontFamily,alignItems,fontStyle, spacing, …) moved intosx;TextField/Dialog/Checkbox/Autocompletelegacy slot props (InputProps,inputProps,InputLabelProps,SelectProps,PaperProps,TransitionProps) moved to the unifiedslotPropsAPI; the removed*Outlineicons were repointed to their*OutlineOutlinedequivalents; and the theme'sMuiButtoncontainedPrimarystyle override was rewritten with the v9variantsAPI. This is a frontend-internal component-library upgrade with no change to application routes, behavior, or backend/API contracts; the full TypeScript type-check, ESLint, production build, and 165-test unit suite pass. - Frontend Build/Test Toolchain Requires Node ≥ 22.22 — The test toolchain was raised to
vitest5 andjsdom30, whose bundledundicirequires a Node runtime API (webidl.util.markAsUncloneable) available only on Node ≥ 22.22. CI and the frontend Docker image already run Node 24;.nvmrcfiles were added at the repository root and infrontend/(pinned to Node 24) so local development selects a compatible runtime automatically. - Auth Cookies Are
SameSite=Lax(OWASP ZAP finding) — Therefresh_tokenandXSRF-TOKENcookies were sent withSameSite=NonewheneverCOOKIE_SECURE=true, which let browsers attach them to cross-site requests. Both are now alwaysSameSite=Lax;COOKIE_SECUREstill controls only theSecureflag. The web interface always calls the API on its own origin, and SSO sign-in (Entra) is unaffected. Existing sessions continue: the refresh cookie gets the new attribute on the next token refresh. - API Cache and Cross-Site Request Protection (OWASP ZAP findings) — API responses now default to
Cache-Control: no-store, no-cache, must-revalidateandX-Content-Type-Options: nosniff, so login, refresh, SSO and status responses are never stored by browsers or proxies; CRL and ACME responses keep their own cache policy. A Fetch Metadata resource isolation policy rejects cross-site browser requests with403unless they are top-level navigations or come from an origin listed inCORS_ALLOWED_ORIGINS. Non-browser clients (agents, gateways, SCEP/ACME/OCSP, CLI, Terraform) are unaffected. If a browser application on another domain calls the API, list its origin inCORS_ALLOWED_ORIGINS. - Organization-Scoped Roles Stay in Their Organization — A role assigned for one organization no longer grants access to another organization's projects, secrets, certificates or rotation runs: the permission check now judges every request in the resource's own organization and project instead of the caller's default organization, and only a role assigned without organization and project counts as global. Roles inside their own organization and global roles work as before. Cached permission decisions are now kept per organization, project, client IP and MFA state. Assigning a role (
POST /api/v1/rbac/users/{id}/roles) with aproject_id,organization_idorenvironmentthat is present but invalid (not a UUID, an empty string, a number) is rejected with 400 instead of being stored as a global assignment. - Secrets Are Created Only in Projects You May Write To —
POST /api/v1/secrets,POST /api/v2/secrets,POST /api/v2/secrets/migrateandPOST /api/v2/secrets/comparetake the project or secret from the request body, and the permission check now judges it there: the caller needssecret:write(compare:secret:read) in that project, its organization or globally, for the environment in the body. Before, a role limited to one project could create a secret in any project, including another organization's, migrate another tenant's secret to zero-knowledge format and compare another project's environments. Such requests now get 403; a migrate batch that contains a secret the caller may not write is refused as a whole, without migrating any of it. - Rotation Configs, Executions and Backups Stay in Their Project —
/api/v1/rotation/configs/{id}(read, update, delete, preflight, trigger),/api/v1/rotation/resources/{kind}/{id}(read, readiness, history, trigger: Entra credentials in their app registration's project, certificate deployment targets and renewals in the certificate's project; system keys, keytabs and service identity secrets for global roles only),/api/v1/rotation/executions/{id}(and/resume),/api/v1/rotation/preflights/{id}and/api/v1/rotation/backups/{id}/…are now judged in the project and organization of the rotation config, execution, preflight or backup they name; an id that does not exist answers 404. Before, a rotation role in one project could read and trigger another organization's secret rotation and reveal or restore its pre-rotation value.POST /api/v1/rotation/configsauthorizes thesecret_idin its body (403/404), and backup reveal/restore checksecret:readin the secret's own project and environment.GET /api/v1/rotation/executions,GET /api/v1/rotation/backupsandGET /api/v1/rotation/resourceslist only what lies in the projects and organizations where the caller holdsrotation:read(all of it, including resources without a project such as system keys, for a global role). Asecret_managercertificate target may write only into a project of the certificate's organization, and saving one needssecret:writein that project (404/403); preflight blocks an existing cross-organization target (target_project_other_organization). - Environment-Limited Roles Are Judged in the Secret's Environment — A role assigned for one environment is now checked against the environment of the secret a request names, not against
?environment=or the default: adev-only role no longer reads, migrates or copies aprodsecret (403).POST /api/v1/secrets/{id}/copychecks the target environment in the secret's project and answers 404 for an unknown secret. - Drift Detection Across All Organizations Needs a Global Role —
POST /api/v1/secrets/drift/detectwithoutproject_idchecks the secret links of every organization; it now answers 403 unless the caller holdssecret:writeglobally. The web interface always sends the project. - Project Roles Count Only in Their Project Outside Route Checks — A project-scoped assignment no longer applies to decisions made without a project (an organization-level rotation backup, a list's scope, a body-scope check). The route check of endpoints without a project or a resolvable id still lets a project role through until those endpoints narrow to their own scope.
- Integrations, Entra Apps, Sync Rules and Secret Links Stay in Their Project — The routes that carry only an integration, Entra app registration, Entra credential, managed subject, Entra sync conflict, sync rule or sync conflict id (
/api/v1/projects/integrations/{id}…incl. database sessions,/api/v1/entra/{integrationId}/…,/api/v1/entra/apps/{id}…,/api/v1/entra/credentials/{id}…,/api/v1/entra/subjects/{id},/api/v1/entra/sync-conflicts/{id}/resolve,/api/v1/projects/sync-rules/{id}…,/api/v1/projects/sync-conflicts/{id}/resolve) are now judged in the project that resource belongs to: a role of another project or organization gets 403, and an id that does not exist 404 (before, some answered 200 with an empty list, 409 or a "failed" dry-run).GET /api/v1/integrations,GET /api/v1/entra/expiry-reportandPOST /api/v1/admin/azure/mi-permissions-checkshow only the integrations and credentials of the projects in which the caller holds the permission. A sync rule, a secret link and an Entra rotation config's post-rotation action may only name an integration of their own project (400 otherwise), a sync rule update no longer changesproject_id(the Terraform resourcemazevault_sync_rulenow replaces the rule whenproject_idchanges), deleting a secret link needs the link's own secret (404 otherwise), and a database integration reads Key Vault references (admin_password_integration_id,wallet_password_integration_id, stored admin credentials) only from an integration of its own project. - Agent Bindings and Discovery Policy Stay in the Agent's Organization —
POST /api/v1/projects/{id}/integrations/agentsbinds only an agent of the project's organization; another organization's agent or an unknownagent_idis answered 400 and nothing is stored (before, any agent could be bound, and an unknown one gave 500).PUT /api/v1/agent-integrations/{id}is now judged in the binding's project: a writer of that project (project:write) can edit it (before, only organization-wide roles could, and they could edit any organization's bindings), a role of another organization is refused and an unknown binding gets 404.GET /api/v1/agents/me/discovery/policybuilds the bundle only from the templates of the calling agent's organization (before, every agent got the oldest organization's templates, including its keystore password candidates); an agent without an organization gets only the built-in defaults. Agents need no change: the request is the same and the organization is taken from the agent's identity. An agent registered without an organization (older registrations) cannot be bound to a project until it re-registers with a deployment token. Bindings created across organizations before this release are not removed automatically: review the agent list of each project (the project's Integrations tab) and unbind agents of other organizations. - Approval Policies and Requests Stay in Their Organization —
PUT/DELETE /api/v1/projects/approval-policies/{policyId},GET /api/v1/projects/approval-requests/{requestId}and its/approveand/rejectactions are now judged in the project the policy or request belongs to. Before, a role in any organization could read another organization's approval request, approve or reject it, and weaken or delete its approval policies. A role of another project or organization now gets 403, and an id that does not exist 404 (before 500 for update, approve and reject, and 204 for delete). A policy update changes only the policy's own settings (name, trigger, conditions, approvers, expiry, notifications, enabled);project_id,idand timestamps in the body are ignored, so a policy can no longer be moved into another project. The Terraform resourcemazevault_approval_policytreats a policy already deleted in MazeVault as deleted onterraform destroy. - Certificate Update and Import Stay in the Caller's Organization —
PUT /api/v1/certificates/{id}with aproject_idnow also needscertificate:importin the target project (403 otherwise), and the service refuses to move a certificate (and its private key) into a project of another organization (400); a template of another organization is now answered 400 as well (before, 500).POST /api/v1/certificates/import,/import/bulkand/import/filejudge everyproject_idof the request: withoutcertificate:importin that project the whole request is refused with 403 and nothing is imported (before, a holder of one project's right could import a certificate and private key into any project, including another organization's). Atemplate_idof another organization than the target project is answered 400 on every import route, and so is atemplate_idwithout aproject_id;PUT /api/v1/certificates/{id}likewise refuses a template for a certificate without a project unless the same request assigns one./importand/import/bulkignoreorganization_ca_account_idandca_idin the body (as the file import already did); the CA account follows the template. The "already exists" answer names the existing certificate's project only to an import into that same project. The Swagger path of the bulk import is corrected from/certificates/import/batchto/certificates/import/bulk(the route itself is unchanged). - Configuration Files and Discovered Certificates Stay in Their Organization —
GET /api/v1/config-files,GET /api/v1/config-files/overview,GET /api/v1/discovery-results,GET /api/v1/discovered-certificatesandGET /api/v1/discovered-certificates/statsnow list and count only the records of the projects and organizations in which the caller holds the read permission (before, every organization's files, discovery results and discovered certificates). A record without a project belongs to the organization of the agent that reported it (a discovered certificate synchronised from a CA: the CA account's organization); an agent without an organization: global roles only.GET /api/v1/config-files/{id},POST /api/v1/discovery-results/{id}/adoptand/ignore, andGET/POST /api/v1/discovered-certificates/{id}(detail,assign,adopt,ignore,archive,import-key) are judged in the record's project or organization: another organization's record answers 403 and nothing changes, an unknown id 404 (GET /config-files/{id}answered 500 before). The target project ofassign,bulk/assign,bulk/adoptand of a discovery-resultadoptmust be one in which the caller holdsdiscovered_cert:assign(for a discovery resultconfig:write; 403 otherwise), andbulk/assign,bulk/adoptandbulk/ignorerefuse the whole request (403) when one of the ids belongs to a scope the caller does not holddiscovered_cert:bulkin. A project role sees and acts on only the discovered certificates already assigned to its project; unassigned ones need an organization role. The target project must belong to the record's organization, also for a caller with roles in several organizations (403; an unknown target project 404 instead of 500), and adoption uses the record's organization. A discovered certificate is linked automatically (agent report, CA synchronisation) only to a managed certificate of its own organization, so another organization's certificate can no longer be moved or revealed through it; assigning a record that is linked to a managed certificate moves that certificate only within the organization (409 otherwise) and now also needscertificate:writeon it and in the target project (403). Links to another organization's managed certificate created before this release stay in place but can no longer move it. Importing or renewing a certificate links only discovered certificates of its own organization, the detail andimport-keyignore an older link to another organization's managed certificate (import-keyanswers 400), and a CA account's synchronisation and adoption no longer give a discovered or managed certificate of another organization that CA account or its order. - Certificate Authorities, CA Accounts and Templates Stay in Their Organization — A CA belongs to the organization of its project or, for an organization-level CA, to the organization whose CA account links it.
GET /api/v1/calists only the CAs of the caller's organizations and projects (all CAs for a global role);GET/PUT /api/v1/ca/{id},POST /api/v1/ca/{id}/hsmandPOST /api/v1/ca/{id}/crl/regenerateon another organization's CA, or on a CA linked to no organization without a global role, are refused with 403. A CA account'sca_authority_idand a certificate template'sca_account_idmust belong to the same organization (otherwise 400), and every issuance path (including renewal and ACME) refuses a template that was linked to another organization's CA account before this release. PKI moderootcreates the organization's own root CA instead of reusing another organization's CA of the same name.POST /api/v1/projects/{id}/ca/{caId}/hsmandPOST /api/v1/projects/{id}/certificates/{certId}/revokenow act on{caId}/{certId}of project{id}(before, they read the project id as the CA / certificate id and never worked); a CA or certificate outside the project is 404. Gateway certificates (POST /api/v1/gateways/csr) are issued only from the instance's systemgateway-mtlstemplate and signed only by an instance CA (one created withPOST /api/v1/ca/initialize, which now requires a global role: 403 for an organization role); a tenant template namedgateway-mtls(a workaround some installations created) is now ignored, and without the system template or an instance CA the answer is 404 (was 500). Templates without a CA (such asagent-mtls) are signed by their organization's internal CA or else the instance CA, never by another organization's CA. System templates (agent-mtls,gateway-mtls) can no longer be edited or deleted (403). A CA'socsp_responder_cert_idmust be a certificate of the CA's organization (400). Issuance, renewal, ACME finalization and DCV all use a template's CA account only within the template's organization. A certificate request (POST /api/v1/certificates/csr,POST /api/v1/projects/{id}/csr) can only use a template of the project's (or the agent's) organization; another organization's template is answered 404, andPOST /api/v1/certificates/csrwithout a project requirescertificate:requestin the template's organization. Upgrade: an organization without its own internal CA and an installation without an instance CA no longer get agent mTLS certificates signed by some other internal CA: agent enrollment fails until the organization initializes its internal CA (Organization Settings → Project Settings → Certificate Authorities → Initialize Internal CA) or a global administrator creates an instance CA (POST /api/v1/ca/initialize). A CA created withPOST /api/v1/ca/initializethat an organization's CA account later linked is that organization's CA, not an instance CA; if it was the only one, gateways get 404 until a global administrator creates a new instance CA. A PKCS#11 HSM whose module cannot be loaded now fails with an error (the device test reports it unreachable) instead of panicking, which stopped the backend when a certificate of a CA configured for it was revoked. - Organization Pages Act on the Organization in the Path —
/api/v1/organizations/{id}/…is now judged in the organization{id}names, not in the caller's default organization: a role scoped to one organization no longer renames another organization, adds its environments, reads its licence or sync settings, or manages its CA accounts, internal CA, HSM devices, renewal policies or ACME (EAB) credentials (403), also not by adding?project_id=of a project of its own organization (403). Items under the path are looked up inside that organization: an environment, renewal policy, HSM device or EAB credential of another organization answers 404 and is left unchanged; deleting one that does not exist (or no longer exists) now answers 404 instead of 204 (environments, renewal policies, EAB credentials) or 400/409 (HSM devices).POST /api/v1/organizations/{id}/acme-credentialsrefuses aproject_id,default_template_idor domain-rule template of another organization (404), and an ACME order no longer uses a default or domain-rule template of another organization stored earlier (without another template the order is refused).PUT/DELETE /api/v1/organizations/integrations/{id}and/api/v1/organizations/templates/{id}, the agent actions/api/v1/agents/{id}/…(update channel, lifecycle impact, unregister, re-register, uninstall) and the deprecated/api/v1/ca-accounts/{id}/productsand/syncare judged in the organization of the integration, template, agent or CA account (an agent without an organization: global roles only); an unknown id answers 404.GET/POST /api/v1/ca-accounts/with anorganization_idother than the caller's needs the CA permission in that organization (403). The Terraform resourcesmazevault_environment,mazevault_renewal_policyandmazevault_hsm_devicetreat a 404 on destroy as already deleted. - Approvals Enforce Four Eyes, Expiry and Single Use — The requester of an approval request can no longer approve it (four-eyes principle), even with
approval:approveandrequired_approvers: 1; a request past itsexpires_atcan no longer be approved, and an approved rotation publish request is no longer honoured afterexpires_at. Both are refused with an error and the request stayspending. Concurrent votes are serialized so the quorum is counted correctly. Creating an approval request through the API no longer accepts server-owned fields (status,policy_id,expires_at,resolved_at,decisions), so a client cannot create an already approved request or votes in other users' names, andrequired_approversis at least 1; the requester's own vote never counts toward the quorum. An approved rotation publish request is now used by only one new rotation intent: when the original rotation intent cannot be reused (environment-bound secrets) or the automatic continuation after approval re-authorizes, the new intent takes over the approval of the waiting intent (same resource, action and approval policy; a user only takes over approvals of their own requests), which is markedsuperseded. Previously such rotations ended on approval required again and never ran. Concurrent triggers of an intent that is reused (its preflight is still valid) are not limited this way yet and can still both use one approval (tracked as F-BEROT-044). - Role and Access Grants Cannot Exceed the Caller's Own Rights — Assigning a role (
POST /api/v1/rbac/users/{id}/roles), removing an assignment, creating or deleting a group mapping (/api/v1/rbac/mappings) and creating a user with arole(POST /api/v1/rbac/users) now require the caller to hold every permission of that role, including the permissions its deny entries (!x) restrict (and theadminrole itself to hand outadmin) through its own role assignments that cover the target scope and do not expire earlier; otherwise the answer is 403. An organization admin manages roles inside its organization only; a user created with arolegets a global assignment, so only a caller holding that role globally may create it (create the user without a role and assign an organization or project role instead). Deleting a user (DELETE /api/v1/rbac/users/{id}) requires the rights to remove each of the user's role assignments. Organization admins and the Access Control page: the page creates users with the global roleuserand assigns roles without a scope (globally), so an organization admin now gets "Failed to create user" / "Failed to assign role" there. Create the user via the API without a role (POST /api/v1/rbac/userswithemailandpasswordonly) and assign the role withPOST /api/v1/rbac/users/{id}/rolesand{"role_id": "<role>", "scope": {"organization_id": "<organization>"}}(orproject_id; project roles can also be assigned on the project's Access tab). A scope whoseproject_idbelongs to another organization thanorganization_id, or an unknown project, is rejected with 400;granted_byis always the caller. Temporary access (POST /api/v1/access/temporary) now accepts the documented body (target_user_id,resource_type,resource_id,permissions,duration_minutes,reason, optionalenvironment); the approver needs<resource_type>:grant_accessin the resource's project or organization and may grant only permissions it holds itself or concrete actions of that resource type, and a grant for one resource no longer applies to requests without that resource. Break-glass (POST /api/v1/access/break-glass) requires theaccess:break_glasspermission and*through a global assignment (in practice a global administrator); refused attempts are audited asGRANT_BREAK_GLASS_DENIED. - Role assignments for every environment (
*) and break-glass access now take effect (review them before upgrading) — A role assignment with environment*now applies in every environment; before, it applied in none and granted nothing. It stays limited to its organization or project and, like any environment-bound assignment, does not apply to a request without an environment (the same holds for*in a temporary grant). A break-glass grant (POST /api/v1/access/break-glass) now gives its holder*on every resource type in every environment until it expires an hour later or is revoked (access decisions are cached for up toCACHE_PERMISSION_TTL_SECONDS, default 5 minutes, so an allow can outlive the expiry by that long); before, it never applied. The archive lifecycle actions still need theadminrole, and a deny entry (!x) of one of the holder's roles still blocksxduring break-glass. Temporary grants for environment*(POST /api/v1/access/temporary) take effect the same way. When several temporary grants match a request, their permissions now add up (before, one of them was picked). Before upgrading, review the assignments that will start to apply withSELECT user_id, role_id, organization_id, project_id FROM user_roles WHERE environment = '*';and the active break-glass and*grants withSELECT identity_id, resource_type, environment, valid_until, reason FROM environment_permissions WHERE (resource_type = '*' OR environment = '*') AND is_active AND (valid_until IS NULL OR valid_until > now());. - Consistency Groups, Renewal Queue Items and Certificate Targets Stay in Their Project —
/api/v1/consistency-groups/{id}(read, update, delete,/check),/api/v1/consistency-warnings/{id}/resolveand/api/v1/renewal-queue/{id}/…(approve, cancel, resume, DCV state, DCV retry and e-mail resend) are now judged in the project of the consistency group or of the queued certificate: a role of another project or organization gets 403, and an id that does not exist 404 (before, a role limited to one project could read, rewrite and delete another organization's consistency group, cancel its certificate renewals and read their DCV records)./api/v1/certificates/{id}/targets/{targetId}…and/api/v1/certificates/{id}/rotation/executions/{execId}answer 404 for a deployment target or rotation execution that does not belong to the certificate{id}; before, they returned another organization's target configuration and execution (a malformed{id}on the target routes now answers 400). Creating or updating a certificate deployment target (POST /api/v1/certificates/{id}/targets,PUT …/targets/{targetId}) accepts only anagent_idof the certificate's organization and anintegration_id/database_integration_idof the certificate's project (400 otherwise); before, a target could name another organization's agent or Key Vault integration and/syncdeployed the certificate with its key there. Targets saved before this release are not re-checked: review the agents and integrations of existing certificate targets. An agent registered without an organization (older registrations) can no longer be set on a target until it re-registers with a deployment token. ?organization_id=and a Bodyorganization_idNo Longer Reach Another Organization — A request that names an organization in?organization_id=(managed tokens, keytabs, certificate templates, deployments, the renewal queue, CA accounts) now needs the route's permission in that organization too, otherwise it is answered 403; before, the role was checked in the caller's organization while the handler worked in the named one. The same holds fororganization_idin the body ofPOST /api/v1/projects/(project:write) andPOST /api/v1/deployments/(deployment:write).GET /api/v1/projects/lists only the projects in which the caller holdsproject:read./api/v1/certificate-templates/{id},/api/v1/naming-conventions/{id}/…andPOST /api/v1/keytabs/discovered/{id}/importare judged in the organization of the template or discovered keytab (an unknown id is 404, before 500);POST /naming-conventions/{id}/provisioncreates projects only in the template's own organization (anotherorganization_idis 403), and a discovered keytab is imported only into a project of its own organization (404). Creating a project needsproject:writeat organization level, in the body organization or, without one, in the caller's organization (a project role no longer suffices); withoutorganization_idthe project is still created only on an instance with a single organization. API and SDK callers that hold only a project role and send?organization_id=of an organization now get 403 on those routes (for example the token and keytab lists); sendproject_idof your project instead where the route takes it, or hold a role in that organization. Withoutproject_ida project role counts on these routes only for a project of the caller's organization (the instance's default organization, in which these routes are judged); before, a project role of any organization acted there with the rights of the whole default organization.- Dashboards, Reports and the Weekly Report Show Only the Caller's Organizations — Without
project_id,/api/v1/dashboard/*(secrets, certificates, configuration and rotation overviews,/exportof every type,/rotation/failures,/rotation/actionable,/sync/overview,/sync/conflicts,/sync/failures),GET /api/v1/certificates/,/api/v1/archived/summary,/projects,/secrets,/certificatesandGET /api/v1/reports/previewnow count and list only the projects and organizations in which the caller holds the permission; before, they covered every organization. Rows without a project (certificates, rotation executions) need a global role; theca_accountsexport lists only organizations in which the caller has an organization role. Acknowledging a rotation failure or a sync failure or blocked seed of another organization is refused (404 or 403); dismissing another organization's actionable rotation answersalready_removedand changes nothing.GET /api/v1/sync-dashboard/eventsand/merkle(replication data of the whole instance) need a globalsync:readrole. Each report-enabled channel (Slack, Teams, webhook, Jira) now gets the weekly report of its own organization only, and so do the e-mail recipients, which are now set per organization (see Weekly-report recipients are set per organization). Compliance report password statistics count only the organization's secrets and templates. - Service Identities Belong to an Organization (check after upgrading) — A service identity now has an
organization_id: it is created in the instance's default organization (the one routes without a project are judged in), or in the organization named by?organization_id=, where the caller needsservice_identity:writein the default organization and in that one, and a role scoped to an organization lists, reads, renames, deletes and manages Universal Auth and client secrets (/api/v1/auth/universal-auth/identities/{id}…, rotation resources of kindservice_identity_secret) only for that organization's identities; global roles keep managing every identity. Before, aservice_identity:*role of any organization managed every tenant's identities. An unknown identity id now answers 404 (before 500 on update). Migration000235assigns each existing identity to the single organization of its unexpired role assignments, else of the user who created it (a creator with a global role assignment does not count), else, on an instance with exactly one organization, to that organization; it removes or disables nothing and Universal Auth sign-in keeps working. On an instance with several organizations an identity it cannot attribute stays without an organization, so only global roles manage it; the migration lists each as aWARNINGline (000235: service identity …) in the PostgreSQL log. After upgrading, list them withSELECT id, client_id, display_name FROM service_identities WHERE organization_id IS NULL;and assign each withUPDATE service_identities SET organization_id = '<organization id>' WHERE id = '<identity id>';.POST /api/v1/service-identities/?organization_id=answers 400 for an invalid id and 404 for an unknown organization. The Terraform resourcemazevault_service_identityexportsorganization_idand treats an identity already deleted outside Terraform as gone. - Offloaded Keys Stay in the Caller's Organization and Vault (Orchestrator Mode) — Importing a certificate with
key_storage_mode: externalaccepts akey_integration_idonly from the organization of the import'sproject_idand refuses it without a project (400); before, a private key could be written through another organization's Key Vault integration. Every key offload (certificates, keytabs, managed tokens) now uses an explicitly named integration only inside the caller's organization, and an offload that names neither an organization nor a project is refused instead of using the oldest secret manager of any organization: in Orchestrator Mode, importing or discovering a private key of a certificate without a project now fails until the certificate is assigned to a project. Reading and deleting an offloaded key uses the Key Vault named in its reference (before, the first Azure integration of the organization, or of any organization, so with two vaults the key was looked up in the wrong one); a reference whose vault no enabled integration of the owning organization holds fails instead. Exporting, deleting or reusing at renewal the externally stored key of a certificate without a project is refused for the same reason. Key custody events of an offload carry the caller's organization also when it is known only from the request context.
Notes¶
- Upgrade Impact (Effective Chain, Discovery Body, Agent Deployment Contract) — Version
1.0.61adds one idempotent, additive migration,000199_discovered_certificate_body(certificate_pem,chain_pemTEXT NULL ondiscovered_certificates; the database health check validates both). No column is added tocertificates, no backfill runs, no existing chain is rewritten. Certificates that already carry a stored chain export, display, rotate and deploy byte-for-byte as before (covered by a regression test); only certificates with an empty chain change behavior, and only when a verified issuer exists in the same organization. Reading (export, detail, agent list) never persists anything; the resolved chain is written only when an import or adoption stores a certificate body that has no chain. API additions are additive:chain_source,chain_complete,chain_warningsonGET /certificates/{id}(and/projects/{id}/certificates/{certId});certificate_pem,chain_pem,chain_certificatesonGET /discovered-certificates/{id}; export of a record without a body now returns422 CERTIFICATE_BODY_MISSINGinstead of a generic 500. Terraform:mazevault_certificatedata source gainschain_pem,chain_source,chain_complete; itscertificate_pemis now populated (it was always empty before because the SDK read a field the API does not emit) — plans that referenced it will show a value for the first time. Behavioral changes to review: (1) a private key import for a managed certificate without a body is rejected until the body exists (the next agent scan, the next CA synchronisation, or a manual import of the public certificate — CRT/PEM/DER or PFX — attaches it; agents still using the legacy/agents/me/discoveryprotocol do not report the body, so records discovered only by such agents are completed by one of the other two paths); (2) deployment targets are validated when saved and when the rotation workflow is built: WebLogic targets needkeystore_path, atrust_store_password_refwhentrust_store_pathis set, andwlst_script_pathfor any restart mode; database wallet targets need an agent,wallet_path, an Oracle provider andupdate_tns_names=false(rac_nodesis refused as well);web_serverandload_balancertargets are refused. Existing targets are not modified — an enabled target that violates these rules now fails its rotation with the target ID and reason instead of being skipped or reporting false success, and it can always be disabled or deleted; the UI editor turns a legacyupdate_tns_names=trueoff on save and shows the alternative for unsupported providers and target types. Review the deployment targets of production certificates forweb_server,load_balancer, non-Oracle Database Wallet entries and wallet targets without an agent before enabling automatic rotation on them; (3) with the agent optioninstall_chain_to_trust_storeenabled, an intermediate CA that previously had no chain will now also install its root into the host trust store on deployment — the same behavior PFX imports with an embedded root always had. Agent rollout: the backend/gateway fix for JKS / PKCS#12 / WindowsMykeystore deployment works with already-deployed agents. TheAgent File (PEM)target,agent_commandsteps (WebLogic restart, Oracleorapki), the public-only semantics ofwindows_root/windows_ca, and Oracle wallet deployment require the 1.0.61 agent; older agents answer those requests with an explicit unsupported proxy message type error and the deployment step fails fast. Oracle and WebLogic deployments are covered by contract tests against the agent protocol — validate them against a realorapki/ WLST host on staging before relying on them in production. The unreachable duplicate discovery-adoption code path (CertificateDiscoveryService,handlers_discovery.go) was removed; its list filters (managed_certificate_id,discovered_by_agent_id, expiry) were merged into the liveGET /discovered-certificatesendpoint as the query parametersagent_id,managed_certificate_idandexpiring_within_days, andPOST /discovered-certificates/{id}/ignorenow accepts an optional{"reason": "..."}body that is stored asstate_reasonand recorded in the audit log — the only two capabilities the removed code had that the live path lacked; adoption, bulk adoption and the detail enrichment were already a superset there. Both live endpoints gained Swagger documentation, and the five never-routed/discovery/certificates*paths disappeared from the Swagger output. There are no new environment variables, Helm values, or release-package format changes. - Upgrade Impact (Certificate Key Custody, CSR Validation, Serial Normalization) — No database migration, no new environment variable, no Helm value, no release-package format change, and no Terraform provider contract change (the
mazevault_certificateresource is CSR-based and immutable; attaching a key is an operator action). API additions are optional and additive:expected_certificate_idonPOST /certificates/importandPOST /certificates/import/file,key_source_filein thepreview-multiresponse,identity_normalizedin thePOST /admin/certificates/backfillresponse, and thefailedvalue in the certificate-requeststatusenum. Behavioral changes to review before upgrading a production inventory: (1) templates with a non-emptyallowed_key_sizesnow reject uploaded CSRs with other key sizes at submission — including for ADCS and external CAs, which previously did not check — so verify the list on templates used with customer-supplied CSRs (an empty list means any size); (2) templates with an explicitsan_confignow enforce it on uploaded CSRs —allow_additional_sansandmax_san_countcolumns are deliberately not used for uploaded CSRs because the template editor never persisted them reliably; (3) on primary startup a background, idempotent pass rewritesserial_number/thumbprint_sha256/thumbprint_sha1only for rows that diverge from their stored DER (hex serials written by ACME/Vault/external-order finalization, uppercase thumbprints); internal-CA, ADCS, DigiCert, Venafi and imported certificates are already canonical and are not touched, CA/CA-account bindings and renewal settings are never modified, and no sync events are emitted; (4) importing a certificate that already exists in another project now returns an error instead of silently attaching material to the other project's record; (5) auto-approved CSR requests whose issuance fails are markedfailed(externally offloaded pending keys are intentionally retained with their reference for operator cleanup — nothing is deleted from a secret manager on a CA failure), and manually approved failures return the request topending. Deferred decisions (documented in the architecture reference): a unique index oncertificates.thumbprint_sha256(pending external orders and legacy duplicates would break upgrades), enforcing template-to-project assignment on CSR submission (requires a MAJOR bump for API/Terraform clients), custom EKU OIDs in the internal CA, and a retry cap / denied-state detection for ADCS orders that stay pending indefinitely. - Upgrade Impact (Rotation Templates) — Version
1.0.61adds one idempotent migration,000195_rotation_template_policy_fields, which adds three columns torotation_config_templates:lead_time_days(INT, default0),grace_period_days(INT, default0), andsecret_custody_mode(VARCHAR, defaultlocal). The database health check now validates the new template policy columns. Themazevault_rotation_templateTerraform resource gains the optionallead_time_days,grace_period_days, andsecret_custody_modearguments, and the Go SDK is updated to match; all additions are additive and backward compatible, with no removed or renamed resource, data source, API endpoint, or SDK contract. There are no new environment variables, Helm values, or release-package format changes. The provider and SDK additionally expose the already-persistedproject_idandretry_delay_secondsfields (no migration), andorganization_idon the resource isOptional+Computed. Caveat: on template create, an explicit0formax_retry_attempts,retry_delay_seconds, ortimeout_minutesis not honored — the server applies its defaults (3/5/10); omit those fields or set a positive value (changing them to0later via update is honored). - Upgrade Impact (Agent Lifecycle) — This feature adds one idempotent migration,
000196_agent_lifecycle_metadata, which adds nullable lifecycle bookkeeping columns toagents(unregistered_at,unregistered_by,lifecycle_reason,lifecycle_reason_category,identity_revoked_at,uninstall_status,uninstall_requested_at,uninstall_completed_at,replaced_by_agent_id); the database health check validates the new columns. A second idempotent migration,000198_deployment_purpose, adds apurposecolumn (VARCHAR, defaultstandard) todeploymentsso an authorized single-use replacement token can be distinguished from a standard enrollment token — only a replacement token may re-enroll a retired agent; the database health check validates this column too. All additions are additive and backward compatible. TheRequireActiveAgentguard on JWT-authenticated agent routes means agents that have been unregistered, revoked, or deleted are now rejected even while holding an unexpired token; re-enrollment through a valid deployment (or single-use replacement) token remains the supported recovery path — older agents remain compatible because they simply re-register when rejected. Four additiveagent:adminAPI endpoints are introduced (/agents/:id/lifecycle-impact,/unregister,/reregister,/uninstall) plus the additiveDELETE /api/v1/deployments/:id(deployment:write). Deployment list responses now omit the bootstrap token (DeploymentResponse), while the create response continues to return it once (DeploymentCreatedResponse) — the Go SDK and themazevault_deploymentTerraform resource are unchanged in contract and still receive the token on create. The Terraform provider'smazevault_deploymentdelete now calls the new delete endpoint (previously a state-only no-op), soterraform destroyinvalidates the enrollment token server-side; the resourceReadalso repopulatesorganization_idso an imported deployment can be destroyed. Registered agents are unaffected. Remote uninstall is opt-in and only attempted for connected Linux packaged installs. There are no new environment variables, Helm values, or release-package format changes for this feature. - Upgrade Impact (Security & Dependencies) — These are dependency and build-time changes only: no database migrations, environment variables, Helm values, or release-package format changes, and no API, Go SDK, or Terraform provider contract changes.
- Upgrade Impact (Frontend MUI v9 & Node toolchain) — The Material UI v9 upgrade is a frontend-internal change with no change to application routes, behavior, backend/API/Go SDK/Terraform contracts, environment variables, Helm values, or release-package format. Operators building the frontend from source now need Node ≥ 22.22 (CI and the frontend container image already run Node 24;
.nvmrcpins Node 24 for local development). Runtime deployment of the pre-built frontend image is unaffected. - Upgrade Impact (Rotation Backups) — This change adds one idempotent migration,
000197_rotation_backup_lifecycle, which addsstatus(VARCHAR, defaultpending),acknowledged_at, andacknowledged_bycolumns torotation_backups, backfillsstatusfromrestored_at, and replaces the old expiry index with a purge-oriented partial index plus a status index; the database health check validates the new columns. One new optional runtime environment variable is introduced —MAZEVAULT_ROTATION_BACKUP_RETENTION_DAYS(default7) — propagated across.env.example, docker-compose, installers, and all Helm values. Four additiverotationAPI endpoints are added under/rotation/backups(listrotation:read; restorerotation:execute; reveal/acknowledgerotation:write, with reveal/restore additionally enforcingsecret:read). All changes are additive and backward compatible — no removed or renamed resource, data source, API endpoint, or SDK contract — and there are no release-package format changes. Because the backup insert path now succeeds, the pre-rotation backup and automatic-rollback machinery become active for the first time; backups needing manual recovery are surfaced via the new endpoints and themazevault_rotation_backups_recovery_requiredmetric. - Upgrade Impact (Enterprise Functions / Deployment Gating) — This is a UI-reorganization and license-enforcement change only: no database migration, no environment variable, no Helm value, and no release-package format change. A new license feature key,
deployment_management, is added to the PoC and Enterprise feature sets derived bygetLicenseFeatures(state-aware: active / grace / expiring), andFeatureLicenseMiddlewareis applied to the/api/v1/deploymentsCRUD group. No API route, request/response schema, Go SDK, or Terraform provider contract changes, and the Swagger surface is unchanged. Behavioral change: tenants on a Small Business or unlicensed plan that previously reached the Deployment CRUD API now receive HTTP 403 and an upgrade banner; PoC and Enterprise tenants are unaffected. The unauthenticated UUID-protected agent bootstrap endpoints remain ungated, so agent installation is not affected. The upgrade-banner copy for SSH, Configuration, and KeyTab was aligned to read "PoC or Enterprise". - Upgrade Impact (Orchestrator Mode Key Offload) — Backend-only change: no database migration, no new environment variable, no API contract change. Two behaviors are intentionally stricter and should be reviewed by operators running Orchestrator Mode: (1) Integration lookup no longer widens beyond the caller's scope. A token, keytab or private-key offload that carries a project/organization scope and finds no enabled
secret_manager/key_storage/hsmintegration in that scope now fails withno enabled key storage integration found for project/organization …instead of silently using the first integration anywhere in the system; an explicitly selectedintegration_idthat does not exist or is disabled is rejected the same way. Make sure every organization that uses managed tokens or keytabs in Orchestrator Mode has an enabled secret-manager integration in one of its projects. (2) Azure Key Vault size limit is enforced before the write. Values whose base64 transport encoding exceeds 25 600 bytes (≈19 200 raw bytes) are refused with400and the exact limit; this is Azure's documented per-secret cap, not a MazeVault restriction — larger values require a HashiCorp Vault or AWS Secrets Manager integration (64 KB) as the project's key-storage target. Secrets created in Key Vault by this release use the new flat naming (mazevault-token-…,mazevault-keytab-…,mazevault-<cn>-<serial>); existing references stored on certificates are honored unchanged (update_versionrolls a new version of the same secret). Nothing is renamed or migrated in Key Vault.
Version 1.0.60¶
Release Date: 2026-07-20
New Features¶
- Token Management — External API Tokens with Mandatory Expiry Tracking and Agent Deployment — A new Enterprise function (PoC or Enterprise license, feature
token_management) for managing externally-issued API tokens — for example Jira or Signi tokens — that can only be renewed manually in the source system's own UI. Each token is stored with a mandatory expiration date and an optional per-token alert lead time (default 30 days); MazeVault raises atoken_expiryincident through the existing notification channels (email, webhook, Teams, Slack, Jira, SMSEagle) before the token lapses, and escalates it to critical once expired. Token values are encrypted at rest (AES-256-GCM) in standard mode, or offloaded to the configured external secrets manager (Azure Key Vault, AWS Secrets Manager, HashiCorp Vault) in Orchestrator Mode. A token can optionally be bound to a project and deployed to the same target types as secrets, reusing MazeVault's shared value-delivery executors: an agent-managed server configuration file (JSON/YAML/ENV key→value, with an optional allowlisted post-install command), a Kubernetes secret, an Azure Key Vault secret, or an AWS Secrets Manager secret (Windows registry / IIS targets are intentionally deferred). A manual renew action records the newly obtained value and its new expiry, resolves the open expiry incident, and re-deploys any targets flagged for sync-on-renewal. Token Management is deliberately separate from Project Key management (project secrets) and Organization System Keys (MazeVault infrastructure keys), and appears under a new Enterprise Functions navigation group. Access is governed by newtoken:read/token:write/token:delete/token:adminpermissions — deployment and renewal requiretoken:write(admin implies it), and revealing a stored token value requirestoken:admin. The feature is fully manageable through the newmazevault_tokenTerraform resource andmazevault_tokensdata source. - Upgrade Impact (Token Management) — Adds two idempotent migrations:
000193_token_management(createsmanaged_tokensandtoken_deployment_targets, seedstoken:*RBAC permissions onto existing roles — org_admin full; operator read/write/delete; user and auditor read-only) and000194_token_target_types(generalizestoken_deployment_targetswithtarget_type/integration_id/configso token delivery reuses the shared secret/certificate executors). There are no new environment variables, Helm values, or release-package format changes — the feature reuses the existing encryption, secret-offload, notification/incident, rotation-step delivery, and license infrastructure. The database health check now validates the two new tables. The Terraform provider gains the additivemazevault_tokenresource andmazevault_tokensdata source; no existing resource, data source, API endpoint, or Go SDK contract is changed or removed. The endpoints are gated by thetoken_managementlicense feature (PoC and Enterprise); without it the/api/v1/tokensAPI returns HTTP 403 and the UI shows an upgrade banner.
Improvements¶
- Admin Batch Triage on Dedicated Rotation and Synchronization Problem Pages — System administrators can now select individual rows or all currently visible rows on Rotation Problems and in each section of Synchronization Problems. The frontend deliberately replays the existing audited single-item actions with at most three requests in flight, reports progress and partial failures, and refreshes the affected problem lists after completion; no unaudited bulk mutation path is introduced. Rotation failures are acknowledged and their linked open incident is resolved when available. Synchronization failures and blocked-seed incidents are acknowledged in their own sections, while pending synchronization conflicts can only be batch-ignored, which changes local conflict status without writing either value to an external provider. “All visible” is intentionally page-bounded and every confirmation states the exact affected count. Individual remediation remains available to non-admin operators with the existing write permissions; batch controls are shown only to the system administrator.
- HashiCorp Vault Transit HSM/KMS Backend —
mazevault_hsm_devicenow supportsprovider_type = hashicorp_vault, backed by the HashiCorp Vault Transit secrets engine. Previously the value was accepted by validation but instantiation failed withunsupported HSM provider: hashicorp_vaultbecause no implementation existed. Vault Transit keys are generated and held by Vault (RSA-2048/3072/4096, ECDSA P-256/P-384/P-521); signing is performed remotely via the Transitsignendpoint so private key material never leaves Vault. The device connectivity test, key listing, public-key retrieval, remote signing (used by internal CA signing and other HSM-routed operations), and key deletion are all implemented. Configuration takesvault_url,token, and an optionalmount_path(defaulttransit). Key-encryption-key (KEK) wrapping remains served by the separate system HSM interface and is out of scope for this provider. - Provider-Aware Certificate Templates for External Commercial CAs — The certificate template form now adapts to the capabilities of the selected issuing CA account's provider instead of showing one fixed field set for every authority. Each external CA has a different API and issuance model, so the form is driven by provider-declared capabilities (exposed on
GET /ca-providers/{type}/schema): providers with a product catalog (SSLMarket, DigiCert) present the certificate product as a dropdown from the CA's synced product list — the certificate type is derived from the selected product and the free-text external-template OID is hidden; providers that require domain control validation expose a per-template Domain Validation Method (email/dns/file), stored on the template asdcv_method(migration000191); ACME issuers continue to show the ACME challenge policy; internal CAs show neither. The SSLMarket provider now resolves the product code from the template's linked CA product (falling back to a free-text code and then the account default) and honors the per-template domain validation method; DigiCert likewise prefers the per-template method. A new optionaldcv_methodargument is available on themazevault_certificate_templateTerraform resource. Existing templates are unaffected: the new column is nullable and empty means "use the provider/account default".
Bug Fixes¶
- Terraform Managed Tokens Now Have a Valid, State-Safe Lifecycle — The
mazevault_tokenresource used the reserved root attribute nameprovider, causing Terraform schema validation to reject the resource. The label is now exposed astoken_provider, with a versioned state upgrader that preserves existing state values. Token reads and deletes now treat HTTP 404 as resource absence while preserving state on authorization, transport, and server failures. Emptydescription/project_idresponses no longer leave stale non-empty state. New tokens can use Terraform 1.11+value_wowithvalue_wo_version, so plaintext is absent from plan and state; legacyvalueremains supported but is explicitly documented as stateful. Import now supports metadata-only management. Migrating an existing resource fromvaluetovalue_wois intentionally not automatic because replacement changes the token ID and cascade-deletes its deployment targets. - Rotation Failure Triage Shows the True Open Total with a Rolling Ten-Item Queue — The Overview widget previously displayed the number of incidents in the API's default 20-row page as if it were the total, so tenants with more than 20 open rotation failures always saw an incorrect count. The widget now uses the existing paginated incident response's authoritative
total, requests only the ten newest unresolved rotation-failure incidents for display, and reloads the first page after each individual close so the next unresolved incident immediately fills the queue. The misleading page-local High/Critical badge has been removed. Overview intentionally remains an individual-triage surface with no selection or batch-close action. - Secrets Dashboard "Missing in PROD" Metric Now Correctly Reflects Cross-Environment Parity — The Secrets Dashboard KPI previously labeled Missing in PROD never inspected production environments or the
is_productionorganization setting. It counts secret keys that exist in at least one active (comparison-enabled) environment but are missing in another active environment — a cross-environment parity signal that requires at least two active environments. On instances with no production environment (for example a test tenant with onlydevelopment,integration,migration, andtesting), this produced a confusing non-zero "Missing in PROD" count. The card is now labeled Missing (Cross-Env) on both the Secrets Dashboard overview and the Reports view, matching the existing Missing Secrets (Cross-Environment) table below it. The underlying cross-environment computation is unchanged — only the misleading naming and label were corrected. - Orchestrator Mode Key Custody Events Persist Reliably — In Orchestrator Mode, offloading a private key (for example a certificate key sent to Azure Key Vault) recorded a custody audit event whose
metadatavalue was an empty string. Becausekey_custody_events.metadatais a PostgreSQLJSONBcolumn, the insert failed withinvalid input syntax for type json (SQLSTATE 22P02)and the custody entry was lost — logged only as a warning — even though the key offload itself succeeded. Custody events now always persist syntactically valid JSON: an unset or blankmetadatavalue is normalized to an empty JSON object ({}) at the write boundary, so every key offload, retrieval, and deletion produces a durable custody audit record. Callers that already supply structured metadata are unaffected. The database health check now also validates thekey_custody_eventscolumns. - SSLMarket Certificate Issuance Corrected to the Live SSLmarket API — Issuing a certificate through an SSLMarket CA account failed with
API request failed with status 400: {"error":["No route found"]}on both standard and Orchestrator Mode instances. The SSLMarket provider had been implemented against a REST shape that does not match the published SSLmarket API. The provider now targets the real endpoints and payloads: orders are submitted toPOST /order/certificate/{product_code}with the flat order body (domain, SANs, years, CSR, the mandatorydv_auth_method, and owner/authorized-contact/technical-contact/invoice fields that fall back to the SSLmarket account defaults when not configured); order detail, certificate download (by order id and format), domain-control-validation tokens, and revocation now use the correct routes; product resolution reads the real{"products":[…]}catalog; and responses are parsed with the API's actual JSON shapes (string identifiers, arraydns_names, and thepaid/requestedorder states). Authentication (X-Auth-Token) and the base URL were already correct and are unchanged. Certificate issuance and the asynchronous external-CA order poller now complete against SSLMarket. - Orchestrator & Sync Secret-Push Audit Events No Longer Fail with a Foreign-Key Violation — In Orchestrator Mode, pushing a secret to an external provider (Azure Key Vault, AWS Secrets Manager, HashiCorp Vault) recorded a
SECRET_PUSH_CREATE/SECRET_PUSH_UPDATEaudit event whoseuser_idwas mistakenly set to the project's ID instead of a user. Becauseaudit_events.user_idhas a foreign key tousers(id), the insert failed withviolates foreign key constraint "audit_events_user_id_fkey" (SQLSTATE 23503)and the audit record was lost even though the external push itself succeeded — so the external secret diverged from the audit trail. Secret-push and sync-seed audit events are now attributed to the initiating user (and, for system-initiated syncs, to the resolved system actor), so they persist correctly. As defense-in-depth, the audit writer now also guarantees durability: if any audit event ever fails to persist because of a bad actor reference, it is retried once with a null (unattributable) actor rather than dropped; only if the database is entirely unreachable is the full event emitted to the central structured log as a last resort. The previous local emergency-log file sink (/var/log/mazevault/emergency_audit.log), which was unusable on read-only container filesystems in Kubernetes, has been removed. A newmazevault_audit_persist_failures_totalmetric makes any last-resort emission alertable. - Merkle Integrity Cache Now Tracks Secret Changes — The incremental Merkle integrity cache recognized only the certificate/keytab event vocabulary (
create/update/delete) and silently ignored the secret service's past-tense events (created/updated/deleted), loggingmerkle cache updater: unknown event typeand leaving the secret integrity cache stale after every secret change. The cache updater now accepts both forms, so secret create/update/delete operations correctly update the Merkle integrity tree. - Rotation Backups Are Now Encrypted and Support Automatic Rollback — The rotation orchestrator was started without its encryptor wired in, so pre-rotation backups degraded to non-restorable version references and logged
rotation backup requested but encryptor not configured — rollback will be limited. Automatic rollback of a failed rotation was therefore unavailable. The orchestrator now receives the system encryptor at startup, so the pre-rotation state is captured as an encrypted backup and automatic rollback is restored. Backups for externalnames_onlysecrets continue to rely on the external provider's own version history, as before. - Entra ID Integrations Accept AKS Workload-Identity Background Authentication — Configuring an Entra ID integration (used for app-registration secret rotation and Microsoft Graph sync) with
background_auth_method=workload_identitywas rejected withunsupported background_auth_method, even though the Microsoft Graph client and the shared Azure credential factory already support AKS federated workload identity. Three separate validation gates — integration create/update, test-connection, and the runtime consistency check used by rotation — defaulted to rejecting the value, so the integration could not be created or, if forced, failed later during rotation withconfiguration is inconsistent. All three gates now acceptworkload_identity, which — likemanaged_identity— requires no static credentials in the integration config: on a workload-identity cluster the runtime performs the federated token exchange for the configured (or webhook-injected) managed-identity client ID. This unblocks Entra credential rotation on AKS workload-identity clusters without a dedicated client-secret app registration. - Spring Actuator Refresh Rotation Step No Longer Crashes on Malformed Configuration — The
spring_actuatorpost-rotation step used unchecked type assertions onactuator_urland on entries of the optionalendpointslist, so a wrong config key (for exampleurlinstead ofactuator_url) or a non-string endpoint caused a worker panic instead of a clear error. The step now validates its input defensively and returns a structured error, and it builds the refresh URL safely so a base URL, a trailing slash, or a URL that already ends in/actuatoror/actuator/refreshnever produces a doubled path. - Post-Rotation Secret Delivery to Key Vault and Other Targets Now Receives the Rotated Value — Post-rotation delivery actions (Azure Key Vault push, AWS/GCP/OCI secret managers, DevOps variables) require the freshly rotated secret value, but the post-rotation action phase rebuilt an execution context that omitted it, so a delivery action logged
new_password not found in input contextand silently skipped the write. The rotated value is deliberately never persisted, so it is now resolved at execution time from the just-updated MazeVault secret — identically whether the action runs on the primary or is delegated to a gateway (the value is fetched by the executing runtime and is never carried in the gateway task payload). Delivery for Entra credential rotations continues to flow through the dedicated seeded delivery workflow. As a hardening measure, the previous Key Vault value captured for rollback is now redacted from the persisted post-action record so no secret material is written to the rotation history. - Azure Managed HSM / Key Vault HSM Devices Can Now Be Tested and Used — Instantiating an
azure_managed_hsmHSM/KMS device — for the device connectivity test as well as any CA signing, key offload, key rotation, or secret encryption routed through it — failed withCredentialFactory is required for AzureKVProviderbecause the HSM device service constructed the Azure provider without a credential factory. The Azure credential factory is now injected into the HSM device service and threaded through the provider factory, so Azure Managed HSM devices initialize with a real Azure credential. - Manual Secret-Manager Integration Sync No Longer Rejects Non-Canonical Type Values — Triggering a manual synchronization on a secret-manager integration could fail with
sync not supported for integration type: secret-managerwhen the integration's stored type used a hyphen instead of the canonical underscore form. Integration types are now canonicalized (lowercased, trimmed, hyphens folded to underscores) when an integration is created, and the manual-sync guard compares against the canonical form, sosecret-managerandsecret_managerare treated identically. Migration000192normalizes any existing non-canonicalproject_integrations.typevalues so exact-match checks (manual sync, sync rules, key offload) stay consistent. - Pull/Bidirectional Sync Rules Require a Target Environment Up Front — Creating a pull or bidirectional sync rule without a
target_environmentwas accepted but later failed at execution deep in the environment canonicalizer withenvironment slug is empty. Sync-rule creation now requires and canonicalizestarget_environmentfor any rule that is not a pure push (push rules derive the environment from the source secret), returning a clear validation error instead of a confusing runtime failure. - ACME Certificate Issuance Now Completes Finalization (Let's Encrypt / ACME CAs) — A v1.0.59 report described ACME issuance passing dns-01 validation but failing at finalize with the error
POST-as-GET requests must have an empty payload/must have a nil body, and this was reproduced end-to-end against a local Pebble server. Two defects were found and fixed. First, MazeVault submitted the CSR to the order URL (order.URI) instead of the order's dedicated finalize URL (order.FinalizeURL); because the order URL is a read-only POST-as-GET resource, posting the CSR body there was rejected by the CA. Second, once the CSR reached the correct finalize endpoint, some RFC 8555-compliant servers (including Pebble) do not return aLocationheader on the finalize response, so the underlying ACME client's internal post-finalize order poll targeted an empty URL and failed even though the CSR had been accepted; issuance now recovers by polling the known order URL and fetching the issued certificate. End-to-end dns-01 issuance through finalize is verified by a Pebble-backed reproduction test (build tagacme_pebble). - Upgrade Impact — Version
1.0.60is a naming and label correction with no database migrations, environment variables, Helm values, or release package format changes. In the dashboard secrets overview endpoint (GET /api/v1/dashboard/secrets/overview) the response fieldmissing_in_prodis renamed tomissing_cross_env. This is an internal dashboard field consumed only by the MazeVault frontend; it is not part of the Go SDK or the Terraform provider, so no integration contract is affected. The cross-environment parity logic and the missing-secrets listing are functionally unchanged. - Upgrade Impact (Orchestrator custody & SSLMarket) — The Orchestrator Mode key custody persistence fix and the SSLMarket provider correction are backend-only changes with no database migrations, environment variables, Helm values, or release package format changes. To issue through SSLMarket, the CA account integration must set the correct
product_code(an SSLmarket account may offer products — such as trial certificates — that are not returned by the API product catalog and therefore must be configured explicitly) and, when the account has no default business data, the owner/contact/invoice settings required by the chosen product.dv_auth_methoddefaults toEmailwhen not configured. - Upgrade Impact (Provider-aware templates) — The provider-aware certificate template feature adds one nullable column via migration
000191(certificate_templates.dcv_method) and one runtime-computed field (template_form) on theGET /ca-providers/{type}/schemaresponse; both are additive and backward compatible. No environment variables, Helm values, or release package format changes. Themazevault_certificate_templateTerraform resource gains an optionaldcv_methodargument; existing configurations continue to work unchanged. - Upgrade Impact (Audit, Merkle & Rotation) — The secret-push audit attribution fix, the audit durability hardening, the Merkle integrity cache fix, and the rotation backup encryption fix are backend-only reliability changes with no database migrations, environment variables, Helm values, or release package format changes. One additive Prometheus counter,
mazevault_audit_persist_failures_total, is exposed; no existing metric, API endpoint, Go SDK, or Terraform provider contract changes. The local/var/log/mazevault/emergency_audit.logfallback is removed in favor of the central structured log, so the last-resort audit sink now works on read-only container filesystems. - Upgrade Impact (Entra WI, Rotation Delivery, HSM & Sync Validation) — These fixes add one idempotent data migration,
000192_canonicalize_integration_type, which normalizes existingproject_integrations.typevalues to their canonical lowercase-underscore form; it is data-only and backward compatible. There are no new environment variables, Helm values, or release package format changes.background_auth_method=workload_identityis now an accepted value for Entra integrations (including via themazevault_integrationAPI surface), and pull/bidirectional sync rules now requiretarget_environmentat creation time. No existing API endpoint, Go SDK, or Terraform provider contract is removed or renamed. - Upgrade Impact (Vault HSM & ACME finalize) — The HashiCorp Vault Transit HSM provider and the ACME finalize fix are backend-only with no database migrations, environment variables, Helm values, or release package format changes. The
hashicorp_vaultHSM device provider is additive; no existing HSM device configuration changes. The ACME finalize fix corrects the certificate issuance flow only; no API endpoint, Go SDK, or Terraform provider schema is added, removed, or renamed. The Pebble reproduction test is gated behind theacme_pebblebuild tag and does not run in normal CI. - Upgrade Impact (Problem Triage UX) — The truthful Rotation Failure Triage total and the administrator batch workflows are frontend-only changes. They reuse the existing incident pagination metadata and existing single-item mutation endpoints, permissions, and audit events. There are no database migrations, API or Swagger contract changes, new RBAC permissions, environment variables, Helm values, release-package changes, Go SDK changes, or Terraform provider changes.
Security & Dependency Updates¶
- Trivy CRITICAL/HIGH Dependency Vulnerabilities Cleared Across All Modules — The dev-pipeline Trivy filesystem scan (
CRITICAL,HIGH,--ignore-unfixed) was failing on fixed-but-outdated dependencies. All affected packages were upgraded to their fixed versions and verified withgo build,go vet, module unit tests, andgovulncheck(0 reachable vulnerabilities), plus a frontend build and the full Vitest suite:- Go —
golang.org/x/text0.37.0 → 0.39.0 (CVE-2026-56852 / GO-2026-5970,norm.Iterinfinite loop) inbackend,cli,k8s-operator, andterraform-provider-mazevault. - Go —
google.golang.org/grpc1.79.3 / 1.80.0 → 1.82.1 (GHSA-hrxh-6v49-42gf / GO-2026-6061, xDS RBAC and HTTP/2 transport) inbackendandterraform-provider-mazevault. - Go —
software.sslmate.com/src/go-pkcs120.7.0 → 0.7.2 (GO-2026-5052) inbackendandagent; this reachable vulnerability was surfaced bygovulncheckeven though Trivy's severity filter did not report it. - Frontend —
axios1.16.0 → 1.19.0 (GHSA-gcfj-64vw-6mp9 and related advisories).
- Go —
- React Router Upgraded to v8 (Major) — The frontend was migrated from
react-router-dom7.17.0 toreact-router8.3.0, which resolves CVE-2026-55685 and GHSA-qwww-vcr4-c8h2. React Router v8 removes the separatereact-router-dompackage; all imports were moved toreact-router(the app is a declarative SPA usingBrowserRouter, so noreact-router/domentry point is required).reactandreact-domwere raised to a minimum of 19.2.7. - Upgrade Impact (Security & Dependencies) — These are dependency and build-time changes only: no database migrations, environment variables, Helm values, or release-package format changes, and no API, Go SDK, or Terraform provider contract changes. The frontend build now requires Node ≥ 22.22 (declared via a new
enginesfield infrontend/package.json); the CI frontend jobs and the frontend Docker image already run on Node 24. The React Router v8 upgrade is a frontend-internal migration with no change to application routes or behavior; the full frontend unit-test suite passes unchanged.
Version 1.0.59¶
Release Date: 2026-07-18
Improvements¶
- Secret Rotation Views Refresh Silently After Background Completion — The Secrets tab now uses the existing per-secret rotation status poller as an event detector. When a background secret rotation reaches a terminal state, MazeVault refreshes only the affected secret through
GET /api/v1/secrets/{id}and updates the visible version counter without reloading the whole secrets table. If the Version History or Rotation Configuration modal is already open for that secret, the modal reloads its version list or execution history in place. No extra global polling, toast, highlight, or full-page refresh is introduced. - Dedicated Access Control for Synchronization Problem Remediation — Synchronization problems now use a dedicated
sync:read/sync:writepermission boundary instead of implicitly tying action buttons toproject:write. Theproject_admin,certificate_manager, andsecret_managerroles can actively remediate synchronization problems, whileauditorand regular users remain read-only. Navigation and the Synchronization Problems page now reflect the user's actual sync permissions. - Sync Failure and Blocked Seed Actions Are Available Directly from the Problem View — The global Synchronization Problems page and the project-level sync conflicts tab now provide confirmed actions for retry, conflict ignore, current sync failure fingerprint acknowledgement, and
sync_seed_blockedincident acknowledgement. The left navigation badge now uses the aggregatesync_problem_count, covering conflicts, current sync failures, and blocked seed incidents. - Synchronization Problem Dismissals Scale with One Batched Lookup — The sync failure listing now evaluates acknowledged current-failure fingerprints with a single batched dismissal query instead of one lookup per failed sync rule. This preserves the existing rule/timestamp/error fingerprint semantics and soft-delete behavior while keeping the Synchronization Problems view responsive as the number of failed rules grows.
- Certificate Exports Include the Issuer CA Chain More Reliably — Certificate export now normalizes stored certificate bundles and, when needed, resolves the issuing internal CA hierarchy through parent CA records. PEM/CRT and PKCS#7 exports include the leaf certificate followed by the issuer chain, while DER remains leaf-only as before.
- Certificate Renewal Readiness Understands Internal CA Accounts — Renewal eligibility, rotation preflight, and rotation resource metadata now resolve internal organization CA accounts through their backing
CertificateAuthority. Internal CA-backed renewals report both the CA account and the underlying signing CA, matching the runtime renewal path. - External CA Domain Validation Is Now Visible and Durable — External CA orders from DigiCert and SSLMarket now expose DCV instructions through registered renewal queue DCV endpoints and the project certificate table. Certificates with pending domain validation show a View Domain Validation action that opens the existing DCV status panel, where operators can inspect DNS/HTTP/email validation details and trigger provider re-checks without leaving the certificate workflow.
- New External CA Certificate Requests Can Wait for Provider Validation — Certificate requests issued through an external CA no longer assume that
SignCSRreturns a certificate immediately. If the provider returns an order ID without PEM, MazeVault stores a pending certificate placeholder, links it to the request, records a durablesubmitted_to_caqueue item, and lets the external CA order poller complete the request when the provider later makes the certificate available. - CA Account Provider Settings Are Persisted and Terraform-Manageable — CA account create/update/sync flows now preserve non-secret provider settings such as DigiCert
organization_id,server_platform_id,dcv_method,certificate_dcv_scope, custombase_url, and SSLMarket defaults in account metadata. The Terraformmazevault_ca_accountresource adds asettingsmap for those non-secret values while keeping API keys and ACME EAB material in write-only credentials. - Terraform Secrets Support Write-Only Values for Ephemeral Passwords — The
mazevault_secretresource now supportsvalue_woandvalue_wo_versionfor Terraform 1.11+ write-only inputs. Operators can generate a password with an ephemeral Terraform resource such asephemeral "random_password"and pass it to MazeVault without storing the plaintext in Terraform plan or state.value_wo_versionis the stored resend trigger: increment it when Terraform should send a new write-only value. The legacyvalueargument remains supported for existing configurations, and server-sidegenerateremains available for MazeVault-generated secrets. - Secret Update API and Go SDK Support Metadata-Only Updates —
PUT /api/v1/secrets/{id}now treatsvalueas optional: omitting it updates metadata and TTL only, while supplying a non-empty value continues to create a new secret version. The Go SDK preserves the existingUpdateSecret(id, value, ...)method and adds a request-based update path that can intentionally omitvalue, which the Terraform provider uses for write-only secret lifecycle management.
Bug Fixes¶
- Synchronization Problems No Longer Lack Action Icons for Authorized Roles — Users who could see problems through
sync:readpreviously often had no way to resolve them because mutations were bound toproject:write. The new sync failure and blocked seed acknowledgement endpoints are protected bysync:write, audited, and intentionally limited to the synchronization problem surface. - Ignoring a Sync Conflict No Longer Requires an External Provider Write — The
ignoreresolution now closes the localsync_conflictsrow with statusignoredand does not write to the target secret manager. This allows operators to permanently defer a known conflict without risking an unintended external value change. - Sync Failure Acknowledgement Applies Only to the Current Failure — Sync failures derived from
sync_rules.last_sync_statusare dismissed by a fingerprint composed from the rule, last sync timestamp, and error. If a later run fails differently, the problem appears again; acknowledgement therefore does not hide new or changed failures. - Rotation Configuration Edit No Longer Shows a Spurious Partial-Load Warning — The secret rotation configuration modal now addresses rotation history and readiness by the canonical rotation resource id (
rotation_configs.id/resource.resource_id) instead of the secret id. This fixes the misleading "Some rotation sections could not be loaded. Available data is shown." warning when opening Secrets → Rotations → Edit for a configured secret. - Secret Version Rollback Works Reliably for Existing Version History — Secret rollback now stores archived version rows with a generated primary key, preserves the original version timestamp instead of stamping the archive time, and updates rollback metadata through the model serializer path. The frontend also surfaces backend rollback
message/errordetails as an error notification instead of replacing them with a generic "Rollback Failed" response. - Legacy Secret Version Rows with Missing UUIDs Are Repaired — Migration
000189_fix_secret_version_null_uuidassigns valid UUIDs to legacysecret_versionsrows that had missing or zero IDs, and theSecretVersionmodel now generates an ID before insert when one is absent. This prevents primary-key collisions and rollback failures on environments that already contain affected history rows. - Manual Secret Rotation No Longer Creates Duplicate Local Versions in Staging — The
pre_rotation_syncstep now compares the external value with the current local secret value before writing a local update. If the values are identical, the step records the pulled value for downstream rotation context without bumping the secret version. This eliminates the staging symptom where one manual rotation produced two new versions and a confusing intermediate system version. - Version History Now Shows the Correct Author for the Current Version — The current (active) version row in the Version History modal was displaying the original creator of the secret instead of the actor who last changed it. The service layer now derives the current-version author from the most recent archived history row, which carries the actor of the last update, exactly as all other history rows do. Automated rotations triggered by the scheduler continue to appear as System; manual triggers show the user who initiated the rotation.
- Certificate Chain Fields No Longer Duplicate the Leaf Certificate — Issuance, import, renewal, ACME completion, and external CA order completion now normalize certificate PEM data at the write boundary.
CertificatePEMremains the current certificate,ChainPEMstores issuer certificates only, andPublicChainPEMstores the full leaf-plus-chain bundle. Existing contaminated chain data is defensively normalized during export. - ACME Issuance Stores Leaf and Chain Separately — ACME issuance now splits the returned order certificates into leaf-only certificate data and a normalized issuer chain. This prevents full ACME bundles from being stored twice or treated as both the current certificate and the chain.
- ACME Bridge Finalization Validates CSR Identifiers and Persists Async ADCS Certificates — MazeVault's ACME server now rejects finalize CSRs whose DNS/IP identifiers are outside the ACME order, uses the RFC 8555 certificate URL path consistently, and creates the tracked
Certificaterow when an ADCS-backed ACME order completes after CA manager approval. - External CA Polling Handles DCV, Pending Orders, and Certificate Downloads Correctly — The external CA order poller now counts only resolved orders as completed work, fetches/stores DCV tokens when a provider reports validation is required, downloads certificate bundles for DigiCert and SSLMarket before finalization, and completes request-originated orders atomically across the certificate, queue, request, and agent assignment records.
- DCV Retry No Longer Resumes Expired Challenges Prematurely — Operator-triggered DCV retry resets expired or stale challenges before re-fetching provider instructions, handles a missing audit service safely in tests/background contexts, and keeps a queue item in
pending_dcvwhen expired tokens remain instead of incorrectly resuming certificate download. - ADCS DCOM Responses Accept Numeric and String Statuses — The backend DCOM parser now accepts both legacy numeric ADCS disposition codes and agent responses such as
pending,issued, ordenied, preserving existing behavior while allowing the agent/backend contract to converge safely. - Renewed Certificates Preserve the Backing Internal Signing CA — Renewals that use an internal organization CA account now preserve the backing
CertificateAuthorityID on the renewed certificate while continuing to sign through the configured CA account provider. External CA account renewals continue to leave the internal CA field empty. - Approval Continuation Audit Events Carry Rotation Context — Automatic rotation continuation after approval now writes audit events with the rotation intent's project and initiating actor when available, improving traceability without changing continuation idempotency or approval enforcement.
- Internal CA HSM Algorithm Inference Is Covered by Regression Tests — The internal CA HSM signer now uses a cleaner type switch for RSA, RSA-PSS, and ECDSA algorithm inference, with tests covering the expected JWA algorithm mapping.
- Terraform Write-Only Secret Updates No Longer Replay or Rotate Values During Metadata Changes — Metadata or TTL updates for a Terraform-managed
mazevault_secretthat usesvalue_wonow call the backend without a plaintext value unlessvalue_wo_versionchanges. MazeVault therefore preserves the existing secret material, version history, offload state, external provider state, and propagation behavior during metadata-only applies. Explicit empty secret values are rejected instead of being confused with omitted values. - Terraform CA Account Provider Types Are Validated Consistently — The Terraform
mazevault_ca_accountresource now rejects empty, whitespace-only, mixed-case, and unsupportedprovider_typevalues before any backend API call. The accepted canonical values are aligned with backend CA account resolvers that can actually connect, includinginternal, therapidsslSSLMarket alias, andvenafi; placeholder I.CA/PostSignum and PSD2 integrations remain excluded until they report a connectable backend status. Venafi account-backed provider resolution is now wired through both CA account service paths, so documented Venafi CA accounts no longer fail in the organization CA-account resolver. Existing documented lowercase configurations continue to work unchanged.
Migration Notes¶
- Migration
000189_fix_secret_version_null_uuidrepairs invalidsecret_versions.idvalues by replacing missing or zero UUIDs with generated UUIDs. The migration is data-repair only and does not change public API contracts. - Migration
000190_sync_problem_actionsadds thesync:writepermission to eligible system roles and creates thesync_problem_dismissalstable for durable acknowledgement of current sync failure fingerprints. The migration is idempotent and does not change configuration schema or environment variables.
Notes¶
- Upgrade Impact — Version
1.0.59contains two database migrations:000189_fix_secret_version_null_uuidfor legacy secret version UUID repair and000190_sync_problem_actionsfor sync remediation permissions and the per-fingerprint dismissal table. Sync-specific API endpoints are added for current sync failure acknowledgement and blocked seed incident acknowledgement; they require no new environment variables or release/package format changes. Terraform write-only secret values require Terraform 1.11+ whenvalue_wois used with ephemeral inputs; existingvalueandgenerateconfigurations continue to work. Secret update now accepts metadata/TTL-only requests without creating a new version, which is an API compatibility expansion. Secret rotation view refresh is frontend-only, and the Version History author fix is a backend service layer change with no configuration impact. The certificate chain, export, ACME, external CA DCV, new-request async issuance, CA account settings, renewal, approval-continuation audit, HSM, SDK, and Terraform provider changes add no additional migrations, environment variables, Helm values, or release package format changes. Terraform CA account provider type validation now rejects invalid values earlier; documented lowercaseprovider_typeconfigurations continue to work.CertificateRequest.statuscan now exposesubmitted_to_cawhile an external CA request is waiting for DCV/provider issuance, and the new renewal queue DCV endpoints reuse existing certificate RBAC permissions.
Version 1.0.58¶
Release Date: 2026-07-16
New Features¶
- ACME Challenge Policy on Certificate Templates — Certificate templates now carry a
challenge_typefield (auto,dns-01,http-01,tls-alpn-01, defaultauto) that controls how ACME validation is performed when the issuing CA account is an ACME provider (Let's Encrypt, ZeroSSL, custom ACME). The policy is enforced at issuance time in the ACME provider:dns-01requires a configured DNS solver and fails fast without one,http-01rejects wildcard identifiers (which ACME cannot validate over HTTP), andtls-alpn-01returns a clear "not implemented" error instead of silently falling back.autopreserves the previous behavior (wildcard → DNS-01 when a solver exists, otherwise HTTP-01). The field is exposed in the Project Templates certificate wizard, in the certificate template detail views, and via the Terraform provider (mazevault_certificate_template.challenge_type). It is ignored for non-ACME issuers (internal CA, DigiCert, ADCS, …). - ACME Account Attributes in the Terraform Provider — The
mazevault_ca_accountresource now supports the ACME account fieldsemail,directory_url,eab_kid, andeab_hmac_key(the HMAC key is marked sensitive/write-only). These map into the backend's encrypted credential store, enabling Terraform-managed Let's Encrypt, ZeroSSL, and custom/EAB-gated ACME CA accounts. The existingapi_key/base_urlattributes remain for API-style providers. The provider now sends the backend-compatiblecredentials/display_namecontract instead of the legacy genericconfigpayload, and write-only credentials are preserved on read (no spurious drift).
Improvements¶
- Single Internal CA — Coherent Lifecycle and Management — The organization's internal Certificate Authority is now managed as a single, first-class object under Organization Settings → Project Settings → Certificate Authorities → Internal Certificate Authority. New endpoints resolve, initialize, and repair the internal CA (
GET/POST /organizations/{id}/internal-ca,POST /organizations/{id}/ca-accounts/{accountId}/initialize-ca), and creating a second internal root is rejected (single-CA guard). The UI provides an Initialize Internal CA action (common name, key size, validity) and an Initialize CA repair action for internal accounts that were previously created without CA key material. OCSP/CRL URLs are editable and CRL regeneration is available directly from the internal CA card. Agents continue to distribute the CA certificate to server trust stores unchanged. - "Add CA Account" Is Now External-Only — The Add CA Account flow no longer offers an Internal provider option (which previously created a non-functional "hollow" account with no CA key material). Internal CA management lives exclusively in the Internal Certificate Authority section. The internal CA is filtered out of the external CA-account cards to avoid duplicate representation, while remaining fully selectable everywhere else (project integrations, certificate template CA binding, ACME/EAB dialogs).
- Strict Renewal Enforcement: Template + CA Required — The certificate renewal pipeline now enforces that every certificate must have a
TemplateIDand the assigned template must have aCAAccountIDbefore renewal can proceed. Certificates without a template or with a template lacking a CA account are rejected with a clear error message at the pipeline entry point. This eliminates the previous multi-level CA fallback chain (cert-level CA, project overrides, internal CA default) and establishestemplate.CAAccountIDas the single source of truth for CA resolution during renewal.
Bug Fixes¶
- Internal CA No Longer Reported as "Not Found" When It Exists — The Certificate Authorities tab previously enumerated project-scoped CAs to display internal CAs, so the organization-level internal CA (which has no project binding) was invisible and the section always showed "No internal CAs found." The section now resolves the internal CA through the organization's internal CA account link and displays it correctly, including its OCSP/CRL configuration.
- OCSP/CRL Configuration Persists for Org-Level Internal CA — Editing OCSP/CRL URLs for the internal CA now uses the CA-scoped endpoint (
PUT /ca/{id}) instead of a project-scoped path that could not address an org-level CA (project_id = NULL). OCSP remains internal-CA-only by design — external CAs (DigiCert, Let's Encrypt, ZeroSSL) continue to advertise their own OCSP/CRL responders via the embedded AIA/CDP pointers. - Integration Deletion Impact Now Excludes Soft-Deleted Secrets — The raw SQL aggregates behind
affectedSecretCountandcollectOrphanedSecretIDsfiltered onlyarchived_at IS NULL, ignoring GORM soft-deletes (deleted_at). This could inflate the reported "total affected" / orphaned counts relative to every other code path that queriessecretsvia GORM (which appliesdeleted_at IS NULLautomatically). Both raw queries now also filterdeleted_at IS NULL, restoring a single, consistent secret population across the delete result, the deletion-impact endpoint, the audit log, and the per-environment breakdown. - Delayed Secret Rotation No Longer Records a Refresh That Did Not Happen —
markDelayedSecretReauthorizingsetrefresh_performed=truein the execution metadata before the single re-authorization call actually ran, so a crash or failure beforeAuthorizeRotationConfigPublishpersisted a misleadingrefresh_performed=trueeven though no refresh completed. The placeholder now recordsrefresh_performed=false; the flag is set totrueonly on the successful re-authorization path. At-most-once semantics are unchanged — the loop guard relies onrefresh_attempted+refresh_generation.
Removals¶
- ProjectCAOverride Removed — The
project_ca_overridestable and all associated code (model, handlers, service methodfindProjectCAOverride) have been removed. This feature was never exposed via the API router (routes were not registered) and the table was always empty in production. The renewal orchestrator now resolves CA exclusively from the template. Migration000188drops the table. buildTemplateFromCertRemoved — The synthetic template fallback for certificates without a template has been removed. Certificates must be assigned a proper template before they can be renewed.
Maintenance¶
- Dead PKI UI Removed — Three orphaned, unreachable frontend components were deleted after confirming no capability loss:
CAManagementTab(its Initialize CA / HSM / CRL capabilities are superseded by the Internal Certificate Authority section) andCertificateTemplatesTab+CertificateTemplateModal(superseded by the variable-driven Project Templates certificate flow, which covers subject DN and SANs via template variables). The liveCertificateTemplateViewModal(used by the project Templates tab) is retained. - Migration 000188 Header Comment Corrected — The header comment in
000188_drop_project_ca_overrides.up.sqlincorrectly referenced "Migration 000187"; it now correctly reads "000188". No functional change.
Migration Notes¶
- Migration
000188_drop_project_ca_overridesdrops theproject_ca_overridestable. This is a non-destructive change as the table was never populated through the application (API routes were never registered). - Certificates without a
TemplateIDthat previously relied on the internal CA fallback will now report "no template assigned" in the rotation dashboard and cannot auto-renew until a template is assigned.
Notes¶
- Upgrade Impact — Version
1.0.58adds two database migrations:000182_add_challenge_type_to_certificate_templates(adds achallenge_type VARCHAR(20) DEFAULT 'auto'column with a CHECK constraint tocertificate_templates) and000188_drop_project_ca_overrides(drops the always-emptyproject_ca_overridestable). Both migrations are idempotent and backward-compatible; existing templates default toautoand existing ACME issuance behavior is unchanged. No configuration schema changes. - Terraform Provider — Existing
mazevault_ca_accountconfigurations continue to work; the new ACME attributes are optional.mazevault_certificate_templategains an optional, defaultedchallenge_typeattribute. The internal CA is intentionally not managed via Terraform — it is managed in the MazeVault UI.
Version 1.0.57¶
Release Date: 2026-07-07
Bug Fixes¶
- Rotation Sync Steps (pre/post_rotation_sync) Now Use Managed Identity Instead of Stale Config Credentials — When the rotation orchestrator's
pre_rotation_syncorpost_rotation_syncsteps resolved Azure credentials viagetAzureCredentialFromConfig, the function auto-detectedclient_secretfields from the encrypted integration config blob even when the integration was configured withbackground_auth_method=managed_identity. This causedAADSTS7000215(invalid client secret) errors during rotation sync steps while the identical Key Vault connection succeeded during non-rotation sync paths. The credential helper now prefers system managed identity whenauth_methodis empty and the system has a configured MI, preventing stale SSO app credentials from being picked up. Additionally, the gateway delegation layer no longer blocks delegation solely because managed identity is present, and delegated sync steps now carry asecret_metadatasnapshot so gateway-executed sync steps can resolve the target secret key without requiring a direct database lookup. - Gateway Delegation No Longer Blocked by Managed Identity Presence —
canDelegateEnvironment()previously returnedfalseunconditionally when the credential factory reported managed identity availability, preventing any Azure KV sync delegation to gateways in environments where MI was configured. This gate has been removed; gateway delegation now relies solely on environment matching and gateway availability, allowing MI-authenticated sync operations to be properly delegated. - Orchestrator Mode Rotation No Longer Performs Duplicate Key Vault Push — In orchestrator mode (
storage_mode=names_only), themazevault_secretrotation step previously calledSecretService.Updatewhich internally pushed the new value to the external vault viaPushSecretToEnvironment. Sincepost_rotation_syncalso pushes the same value to the vault, every rotation produced a redundant duplicate write. The step now callsBumpVersion()(local version counter increment only) in orchestrator mode and defers the sole external write topost_rotation_sync. - Orchestrator Mode Rotation Compensate No Longer Fails on Empty EncryptedValue — When a rotation saga rolled back the
mazevault_secretstep in orchestrator mode,Compensate()attempted to decrypt the previous version'sEncryptedValuewhich is alwaysNULL/empty fornames_onlysecrets. This caused spurious "partially_rolled_back" statuses. The compensate path now returnsnilimmediately for orchestrator-mode secrets — rollback of the external vault value is handled byPostRotationSyncStep.Compensatewhich has the per-integration pre-overwrite snapshot. - Pre-Rotation Sync No Longer Round-Trips Value Back to Key Vault in Orchestrator Mode — When
pre_rotation_syncdetected a newer value in Azure Key Vault, it calledUpdateSecretwhich in orchestrator mode pushed the same value right back to the vault (redundant network call). In orchestrator mode the step now captures the KV value asprevious_valuecontext for downstream steps without triggering a local DB write or external push. - Agent Discovery Report No Longer Silently Drops Metadata Update —
ProcessDiscoveryReport()persisted discovered certificates into the database but never updated the agent's own metadata (last_discovery_at,discovered_certificates_count). After a successful discovery run the agent row remained stale, making it impossible for operators to tell from the dashboard whether an agent had ever performed discovery or how many certificates it found. The transaction now concludes with an atomic count query and agent row update so dashboard stats reflect reality immediately after each report. - Agent Version Not Persisted from Health Heartbeat —
UpdateHealth()stored the full health payload into thehealth_statusJSONB column and refreshedlast_seen, but never extracted theagent_versionstring into its dedicated column. Agents reporting their version via the heartbeat appeared as version-unknown in the UI. The handler now copiesagent_versionfrom the health map into the agent model before saving. - Empty Environment Dropdown in Bind Agent Dialog — The "Bind Agent" dialog on the Project Integrations tab fetched environment data from
GET /projects/:id/environment-settings(which returnsProjectEnvironmentSetting[]with anenvironmentfield) but rendered the list expectingEnvironment[]objects (withslugandnamefields). Because the field names didn't match, every dropdown item appeared blank. The dialog now fetches fromGET /organizations/:orgId/environmentswhich returns the correctEnvironment[]shape, populating the dropdown correctly.
Version 1.0.56¶
Release Date: 2026-07-01
Improvements¶
- Release Pipeline Security Gating Expanded — The development CI pipeline now scans all shipped images, including
docsandinit-certs, and the release pipeline now scansdocsas well and fails the release on CRITICAL/HIGH Trivy findings instead of reporting them passively. This closes a blind spot where auxiliary images could ship with unresolved vulnerabilities even whenbackend,frontend, andocspwere clean. - Base Image and Local Runtime Alignment —
init-certsnow builds from the pinnedDockerfile.init-certspath in localdocker-composeinstead of running an ad-hocalpine:latestbootstrap command. Theinit-certsimage moved to Alpine 3.21 with a package upgrade during build, and the docs runtime stage now refreshes Alpine packages before packagingnginx. This reduces drift between CI artifacts and local runtime behavior and lowers exposure to known OS-package CVEs. - Backend Dependency Refresh for Reachable Integrations — Patched Go versions are now pinned for
github.com/Azure/go-ntlmssp,github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream,github.com/aws/aws-sdk-go-v2/service/s3,github.com/quic-go/quic-go, andgo.mongodb.org/mongo-driver, covering reachable optional paths such as ADCS NTLM authentication, S3 audit archive transport, QUIC stack usage, and MongoDB reconciliation and rotation code.
Bug Fixes¶
- Request ID Tracing Normalized Across Middleware and Logs —
RequestIDMiddlewarenow populates bothrequestIDand the legacyrequest_idGin context key while continuing to emit theX-Request-IDresponse header, and environment-resolution warnings now read the canonicalrequestIDkey. This removes a traceability gap where some logs emitted an empty request ID even though a request ID had already been assigned. - Orchestrator Mode Guard Uses Exact Route Patterns — The orchestrator ingress guard no longer relies on raw URL suffix and substring heuristics. It now matches registered Gin route patterns via
c.FullPath()for secret write routes in both/api/v1/secretsand/api/v2/secrets, while avoiding false positives on nested certificate import flows. Direct secret payloads carryingvalueremain blocked in orchestrator mode, but legitimate certificate-import endpoints are no longer at risk of accidental interception. - Entra Selected-App Sync Now Stays Pending Until Scoped Bindings Exist — When an Entra integration is configured with
selected_appsscope but no selected application bindings have been saved yet, a manual sync now returns HTTP 409 Conflict instead of being reported as a generic failure. The integration is recorded withlast_sync_status = pending,last_sync_errorstays empty, and the hourly scheduler logs a skip until at least one selected application is configured. This makes the API and operational status truthful during staged onboarding. - Sync Rule Status and Audit Surfaces Now Preserve Execution Provenance — Sync executions now persist a canonical execution record and propagate the resulting
execution_id,trigger_source, trigger secret/environment, and aggregate outcome counts into rule status and sync-log metadata. Bidirectional sync also suppresses the immediate echo-push of secrets that were just pulled or left unchanged by the pull stage, reducing pointless external churn while keepingsync_rules.last_sync_statusandproject_integrations.last_sync_*aligned with the final outcome. - Rotation Step 0 (connection_validation) Now Respects Integration background_auth_method — When the rotation orchestrator executes locally (non-delegated path), the
TestConnection()method for Azure Key Vault integrations now callsprepareAzureIntegrationRuntimeConfig()before attempting the connection. Previously, staleclient_secretcredentials in the encrypted integration config would override the configuredbackground_auth_method=managed_identity, causingClientSecretCredential authentication failederrors during rotation while sync (which already used the correct preparation path) continued to succeed. The fix ensures auth method resolution is consistent across sync and rotation execution paths.
Notes¶
- Upgrade Impact — Version
1.0.56contains no database migrations and no configuration schema changes. Existing API contracts remain stable; the main operational change is stricter release gating, so CI and release jobs can now fail ifdocsorinit-certsimages contain unresolved CRITICAL/HIGH findings. - Local Development Impact — The first
docker compose up --buildafter upgrading rebuilds the dedicatedclient-init-certsimage instead of downloading a generic Alpine base and running inline package installation. Build time may increase slightly, but local behavior now matches the shipped image path more closely.
Version 1.0.55¶
Release Date: 2026-06-29
New Features¶
- Secret Rotation Targets — Full CRUD management for secret rotation targets is now available via API, frontend, Go SDK, and Terraform. Targets define the deployment destinations (Kubernetes secrets, database password rotation, agent sync, DevOps pipeline variables, cloud vaults) that MazeVault pushes updated credentials to immediately after a rotation completes. The new
SecretRotationTargetListcomponent in the Secrets tab lets operators add, edit, and remove targets without leaving the project view. The Terraform resourcemazevault_secret_rotation_targetenables fully declarative management; theconfig_jsonargument accepts ajsonencode()-encoded JSON object describing the target-specific configuration. - Internal CA Configuration Update + AIA Backfill — Two new API endpoints allow updating mutable fields on an internal CA account without recreating it:
PUT /api/v1/ca/:idandPUT /api/v1/projects/:id/ca/:caIdacceptocsp_url,crl_url, andocsp_responder_cert_idwith patch semantics (omitted fields are left unchanged). A companionPOST /api/v1/admin/certificates/backfill-aiaendpoint retroactively copies the current OCSP and CRL URLs from a CA account into all existing certificates it issued. OCSP URL, CRL Distribution Points, and Issuer Certificate URL extensions are now properly embedded in the x509 template insideInternalCAProvider.SignCSR()for all newly issued certificates. - Agent Selection in Rotation Config UI — The
SecretPostRotationActionsPanelandSecretRotationTargetEditornow expose a dropdown that allows an operator to bind a specific registered agent to a rotation target. This gives precise control over which on-premise agent executes a deployment step without relying solely on environment-based routing. - Certificate Template View Modal — A new
CertificateTemplateViewModalcomponent provides a full-detail read-only view of any certificate template (SAN patterns, key usage, extended key usage, validity period, CA account binding) without navigating away from the current page. The modal is accessible from both the organisation-levelCertificateTemplatesTaband the project-levelTemplatesTab. The view now also surfaces the signature algorithm (falling back to the CA default when unset) and the ACME profile name, and annotates validation-only constraints and external-CA-governed fields so operators understand which settings are enforced by MazeVault versus the issuing CA. - Certificate Templates Now Govern Issuance End-to-End — Certificate templates have been promoted from a partially-decorative metadata record into the authoritative governance "cookbook" for certificate issuance across the full lifecycle. Template fields that were previously stored but never applied are now honoured by the signing engine and the CSR generator:
max_path_length(with explicit path-length-zero handling for CA certificates), certificate policy OIDs (policy_identifiers/certificate_policies),signature_algorithm, the default common-name template (cn_template), and the subjectemail. A new Governance tab inCertificateTemplateModalexposes approval requirements, allowed environments, and allowed key sizes, and a dedicated Renewal & Rotation section makes the key-reuse policy independently settable. Template defaults are now normalised on create/update (validity_days→ 365,key_size→ 256/2048 by algorithm, min/max validity windows) so a template can never persist inert zero values. - Project & Config Template View Modals — Two new read-only detail modals,
ProjectTemplateViewModalandConfigTemplateViewModal, bring the same at-a-glance inspection experience already available for certificate templates to project templates (general settings, environment rules, variable schema, protocol configuration) and configuration templates (metadata, definition summary, raw JSON). Both are reachable via a view (eye) action in their respective management tabs. - Terraform: Certificate Rotation Config, Entra Rotation Config, and Rotation Resources Data Source — Three new Terraform surfaces complete IaC coverage of the rotation platform:
mazevault_certificate_rotation_configmanages automatic renewal scheduling and post-rotation action lists for a specific certificate;mazevault_entra_rotation_configmanages Entra ID credential rotation settings including days-before-expiry threshold and staged-rotation behaviour;mazevault_rotation_resourcesis a data source that lists all rotation-managed resources with their current status, filterable bykindandenvironment_scope.
Environment Identity Reform¶
- Environment Identifiers Are Now Stored Verbatim and Matched Exactly — Environment identifiers entered in Organization Settings are the single source of truth. The system now stores them verbatim (case-preserving) and matches them exactly (case-sensitive) everywhere — RBAC, secrets, sync rules, gateway routing, gateway tasks, environment locks, and the frontend. Identifiers that differ only in case (for example
developmentA,DeveLopmentB,DeveLopmentC) are treated as distinct environments. The system never silently rewrites, lowercases, trims, or alias-maps what an operator entered. CanonicalizeEnvironmentis now validate-only: it rejects empty/whitespace-only, reserved (*,default,all,system,none), too-short/long, and malformed identifiers (allowed shape^[A-Za-z][A-Za-z0-9_-]{1,31}$), and returns the input unchanged on success.- The gateway environment alias map (
pro→production,npr→nonproduction, etc.) has been removed from both backend and frontend.SupportsEnvironment(),GetEnvironmentMode(), gateway routing, health-monitor failover, and the frontendenvironmentshelper now compare identifiers exactly. The frontend environment helper no longer appliestoLowerCase()/token normalization, and all environment selectors source their options exclusively from the organization environment list. - Impact: existing customer environment data is uniformly lowercase, so exact case-matching is a no-op for current records — zero RBAC/secret/sync regression. Mixed-case identifiers are supported going forward only.
Improvements¶
- Rotation Pre-Execution Probe Completeness (Gateway, Agent, and Entra Runtime) — The rotation orchestrator now verifies every required execution target is reachable before the first mutating step, and returns a structured HTTP 412 error when a rotation cannot safely start. Three new error codes —
rotation_blocked_no_gateway,rotation_blocked_agent_offline, androtation_blocked_runtime_unavailable— are surfaced instead of an opaque 500/409. The probe is now certificate-aware (it resolvesCertificateRotationConfigtargets correctly), collects all required agent IDs across every agent-bearing workflow step, and is also enforced insideexecuteCertificateWorkflow. Entra credential rotation runs the same runtime probe inRotateCredentialWithRequestbefore the lifecycle transitions torotating, so a blocked runtime never leaves a credential half-rotated. A credential or certificate change that cannot be deployed now fails fast and visibly rather than starting and stalling. - Gateway Delegation for Azure Key Vault Sync — Azure Key Vault push and pull sync operations are now delegated to the appropriate gateway when the backend detects that the direct network path to the Key Vault endpoint is not available. Gateway tasks carry the integration configuration and perform the actual Azure SDK calls; the primary backend records only the resulting sync state. The sync rule scheduler start has been deferred to after gateway delegation is fully initialized, preventing transient DNS resolution errors during backend startup.
- Rotation Config — Target Environment Auto-Fill — When
GetConfigBySecretIDcreates a new rotation configuration for a secret that does not yet have one,target_environmentis now automatically populated from the secret's own environment. This eliminates a manual follow-up update step that was previously required before the first rotation could be triggered.
Bug Fixes¶
- Gateway Environment Matching Reworked to Verbatim/Exact Identity — Earlier in this release cycle, gateway environment matching relied on a case-insensitive alias map (
pro→production,npr→nonproduction, etc.) that could silently map unrelated identifiers together and mutate operator-entered values. This approach has been replaced by the verbatim/exact environment-identity model (see Environment Identity Reform above):SupportsEnvironment()andGetEnvironmentMode()now compare exactly, the alias map is removed, and the previously planned alias-normalization migration000176has been neutralized to a no-op (it was never shipped to customers). Forward migrations000178/000179remove the lowercase-enforcing CHECK constraints and case-insensitive unique indexes so case-distinct identifiers are accepted. - AIA Extensions Not Embedded in Issued Certificates —
InternalCAProvider.SignCSR()readocsp_urlandcrl_urlfrom the CA record but never wrote them into the x509 certificate template, so every certificate issued by an internal CA had empty Authority Information Access and CRL Distribution Points extensions. Both extensions are now correctly embedded for all new certificates. Existing certificates can be retroactively updated via the new backfill endpoint. - Device Fingerprint — Concurrent Insert Race Condition — The anomaly detection service could produce duplicate-key constraint violations when two concurrent authentication requests from the same previously unseen device tried to register its fingerprint simultaneously. The insert path now uses an upsert pattern with an
ON CONFLICT DO NOTHINGguard to handle concurrent registrations gracefully. - Sync Rule Scheduler — DNS Errors at Backend Startup — On backends configured with gateway delegation, the sync rule scheduler's first scheduled execution could fail with DNS resolution errors because it started before the gateway delegation subsystem had completed initialisation. The scheduler start is now deferred until the delegation layer is ready.
- Terraform Organization Resource — Delete Silently Swallowed Errors — The
Deletemethod in the Terraformmazevault_organizationresource returned success even when the backend responded with a non-2xx status code. Backend errors are now surfaced as Terraform diagnostics soterraform destroyfails visibly instead of leaving the resource in an inconsistent state. - Certificate Policy OIDs Silently Dropped from Issued Certificates (Go 1.24+) —
InternalCAProvider.SignCSR()populated only the deprecatedx509.Certificate.PolicyIdentifiersfield. Go 1.24+x509.CreateCertificateemits the Certificate Policies extension from the newPolicies([]x509.OID) field instead, so template-declared policy OIDs were silently omitted from every issued certificate.SignCSRnow populates both fields — the modernPoliciesslice (for current encoders) and the legacyPolicyIdentifiersslice (for older parsers) — so policy OIDs are reliably embedded. - Certificate Template Signing & Subject Fields Were Inert —
max_path_length,signature_algorithm, certificate policy OIDs, the default common-name template, and the subjectemailwere persisted on certificate templates but never reached the issued certificate or generated CSR. All of these template fields are now applied during signing and CSR generation, closing the gap between what a template declares and what a certificate actually contains. - External CA Template Import Persisted Zero
validity_days/key_size— Templates imported from external CA providers (ADCS, SmallStep) were stored withvalidity_days = 0andkey_size = 0, which then surfaced as invalid defaults in the template editor. Imported templates now carry sane defaults (key_size = 2048,valid_days = 365), and the service layer normalises any remaining zero values on create/update as a defence-in-depth backstop.
Database Migrations¶
000176_normalize_gateway_environments— Neutralized to a no-op (SELECT 1). This migration originally normalized legacy environment aliases to canonical slugs, but the environment identity reform reversed that direction (identifiers are now stored verbatim). Because the migration was never released to any customer, both its.up.sqland.down.sqlare now documented no-ops, leaving customer gateway data untouched.000177_certificate_templates_signature_algorithm— Adds thesignature_algorithm VARCHAR(50)column tocertificate_templates(idempotentADD COLUMN IF NOT EXISTS) so templates can pin the issuance signature algorithm. The matching.down.sqldrops the column.ExpectedColumns["certificate_templates"]indatabase_health.gowas updated accordingly.000178_relax_canonical_environment_check— Drops the 11chk_*_canonicalCHECK constraints (added by migration000125) that requiredcolumn = LOWER(column)on every environment-bearing column. These constraints would reject case-distinct identifiers, contradicting the verbatim contract; application-side validation (CanonicalizeEnvironment) continues to enforce shape, length, and reserved-word rules. The down migration re-adds the constraints. Idempotent (DROP CONSTRAINT IF EXISTS).000179_case_sensitive_environment_indexes— Replaces the case-insensitiveLOWER()unique guardrails from migration000122with an exact, case-sensitive unique indexuniq_environments_org_slug (organization_id, slug)and restores plain raw-column lookup indexes for every environment-bearing column. Existing per-project uniqueness (idx_project_env) is already exact. The down migration restores theLOWER()indexes. Idempotent.
Version 1.0.54¶
Release Date: 2026-06-27
Bug Fixes¶
- Entra Credential Watchdog — Stuck Detection Permanently Bypassed by Hourly Sync — The PostgreSQL trigger
trg_entra_creds_updatedrefreshesupdated_at = NOW()on everyUPDATEtoentra_credentials, including the non-state field writes performed by the hourly reconciliation sync (syncedEntraCredentialUpdates). This meantupdated_at < now() - 30minwas never true for any credential that went through a sync cycle, preventing the watchdog from ever firing. A newrotation_started_at TIMESTAMPTZcolumn (migration000175) is set whenlifecycle_statetransitions torotatingand cleared on rollback or watchdog recovery. The watchdog query now usesrotation_started_at IS NULL OR rotation_started_at < cutoff;IS NULLcovers credentials already stuck before the migration was applied. - Entra Expiry Monitor —
Preload("")GORM Error on Every Hourly Check —checkExpiringCredentialscalled.Preload("")(empty string) on the GORM query. GORM v2 rejects this withunsupported relations for schema EntraCredential, logging an error every hour and preventing theexpiring_soonlifecycle state from being set on credentials that genuinely are expiring. The invalid.Preload("")call has been removed; behavior is otherwise unchanged. - Sync Rule Pull —
secret_versions_created_by_fkeyFK Violation for System Actors —SyncRuleService.executePullcallsSecretService.Updatewithreq.UserID = uuid.Nil(no authenticated user).Updateunconditionally stored&req.UserIDascreated_byin the newSecretVersionrow; GORM serializes*uuid.Nilas the string'00000000-...'rather than SQLNULL, which violates the non-null FK referencing theuserstable. The fix adds a nil-guard:created_byis set toNULLwhen the caller supplies a zero-value UUID, matching the nullable column contract. - Azure KV Integration — Synced Secrets Displayed as "Stored Locally" —
syncAzureKeyVaultLocalcreated and updated secrets in thesecretstable but never inserted aSecretIntegrationLinkrow withlink_purpose = 'sync_source'.GetSecretSyncStatustherefore returnedlocal_onlyfor every KV-synced secret and the UI showed "Stored Locally" instead of "Synced from KV". The fix inlines the same upsert logic used bySyncRuleService.upsertPullLinkdirectly inIntegrationServiceusings.dbandclause.OnConflict, avoiding a cross-service dependency.
Improvements¶
- Role Permissions —
agent:adminAdded tosecret_managerandcertificate_managerRoles — Agent management operations (agent:admin) have been added to thesecret_managerandcertificate_managersystem roles (migration000174). Operators holding only one of these roles can now register and configure agents without requiring a separateadminrole assignment.
Database Migrations¶
000174_agent_admin_for_managers— Grantsagent:adminpermission to thesecret_managerandcertificate_managerbuilt-in roles.000175_entra_credentials_rotation_started_at— Addsrotation_started_at TIMESTAMPTZtoentra_credentials. Includes partial indexidx_entra_creds_rotation_startedover(rotation_started_at)for therotatingandpending_verificationlifecycle states.
Version 1.0.53¶
Release Date: 2026-06-26
Bug Fixes¶
- OCSP — Certificate Existence Not Verified Before Stapling — The OCSP service responded to stapling requests without first confirming that the referenced serial number exists in the local certificate store. An attacker with a forged or recycled serial could have elicited a valid OCSP response for a non-existent certificate. The service now verifies certificate existence before constructing a response, returning
Unknownstatus for unrecognised serials. - Rotation Step — PostgreSQL Grants Vulnerable to SQL Injection —
rotation_steps/postgres_db.goconstructedGRANT/REVOKEstatements by string-concatenating the caller-supplied role name and privilege list without quoting. Database role names are now double-quoted usingpgx-style identifier escaping, closing the injection path. - SSH Keys —
ExportPrivateKeyMissing Authorization Check —ExportPrivateKeydid not verify that the requesting user had ownership or admin rights on the SSH key before returning the encrypted private material. The handler now enforces the same project-membership and ownership check applied to all other SSH key mutation endpoints. - SSH Rotation — Incorrect API Response Field Mapping for Key Pairs — The SSH rotation response handler mis-mapped key-pair fields, causing the returned
public_keyandkey_idto be swapped or empty after a successful rotation. The field mapping has been corrected. - Keytab Rotation — Unstructured Logging Bypassing Structured Pipeline — Keytab rotation errors were emitted via the legacy
logpackage, bypassing the structured logging pipeline and losing request-scoped fields. All log calls inkeytab_rotation_executor.goare now routed throughslog. - CA Accounts —
ca_authority_idNot Persisted on Update —UpdateCAAccountsilently discardedca_authority_idwhen updating an existing CA account because the field was absent from the GORMUpdatesmap. The field is now included and covered by a new test. - CRL / Revocation Schema Drift — OCSP Returns 500 — The
revocation_entriesandcertificate_revocation_liststables were created by migration000005with legacy column names (reason_code,crl_pem) that diverged from the current GORM model fields (revocation_reason,raw_content). GORM appendsdeleted_at IS NULLto every query; becausedeleted_atwas absent from the production schema the entire CRL/OCSP subsystem returnedSQLSTATE 42703errors. Migration000173adds all missing columns with idempotentADD COLUMN IF NOT EXISTSguards and backfills values from the legacy columns.
Improvements¶
- Rotation Trigger — Request Body Optional — The rotation trigger endpoints now accept requests with an empty or absent body;
reasondefaults to"manual"when not supplied. - CA Internal — HSM OCSP Signing Deferred with Explicit Documentation — OCSP response signing via HSM is explicitly deferred; the code path now carries a clearly marked comment and returns a software-signed response in the meantime, preventing silent fallbacks.
- Feature Flags — Gateway Mode and License Validation Hardened —
features.gotightens the evaluation logic forgateway_modeand license-gated features, eliminating a class of false-positiveenabledresults when the license payload is partially parsed. - SRP — MFA Step Sequencing Documented — The SRP session-verification flow now carries an explicit comment documenting MFA step ordering and the rationale for the current TOTP/backup-code sequence.
- Secret Naming Policy Wizard — Auth Context Threaded to Token Management — The
SecretNamingPolicyWizardnow passes the authenticated user context through to token-management calls, closing a potential unauthenticated call path in the wizard's save flow.
Database Migrations¶
000173_fix_revocation_crl_schema_drift— Adds missing columns torevocation_entries(crl_id,revocation_reason,updated_at,deleted_at) andcertificate_revocation_lists(raw_content,updated_at,deleted_at). Backfills from legacy columnsreason_codeandcrl_pem. Fully idempotent.
Version 1.0.52¶
Release Date: 2026-06-23
Bug Fixes¶
- Renewal Policy Schema —
key_reuse_enabledandvalidity_durationMissing from Database — Thecertificate_renewal_policiestable was created by migration000010using the column namereuse_private_key; the Go model was later renamed tokey_reuse_enabledwithout a companion migration, causing every write that touched the field to fail at the database layer. Migration000172addskey_reuse_enabled BOOLEAN NOT NULL DEFAULT FALSE(with a backfill from the legacyreuse_private_keycolumn) andvalidity_duration INT NOT NULL DEFAULT 0. The same migration convertsnotify_emailsfrom JSONB to TEXT using a three-step staging approach (add TEXT column → UPDATE via set-returning function → drop JSONB column → rename), working around the PostgreSQL restriction that forbids subqueries insideALTER COLUMN TYPE … USING. - Renewal Queue —
certificates.organization_idColumn Does Not Exist —GetRenewalQueuefilteredWHERE certificates.organization_id = ?but thecertificatestable only carriesproject_id; organization is reachable viacertificates.project_id → projects.organization_id. The service now performs a second JOIN (JOIN projects ON projects.id = certificates.project_id) and filters onprojects.organization_id. - SDK and Terraform Provider —
notify_days_before []intSemantic Mismatch — The Go SDK (sdks/go/models.go) and Terraform provider (internal/resources/renewal_policy.go) declared anotify_days_before []intfield that has never existed in the backend. The backend stores a plain comma-separated string undernotify_emails. Both were rewritten to usenotify_emails string, and the two new fieldskey_reuse_enabledandvalidity_durationwere added to align with the live API contract. Acceptance tests that were blocked witht.Skipdue to these gaps are now live.
Database Migrations¶
000172_fix_certificate_renewal_policy_schema— Addskey_reuse_enabled BOOLEAN NOT NULL DEFAULT FALSE(backfilled fromreuse_private_key),validity_duration INT NOT NULL DEFAULT 0, and convertsnotify_emailsJSONB → TEXT tocertificate_renewal_policies.
Version 1.0.51¶
Release Date: 2026-06-22
New Features¶
- Acknowledge Rotation Failure — Operators can now permanently dismiss a reviewed rotation failure from the Rotation Problems dashboard without deleting the underlying execution record. A new
POST /api/v1/dashboard/rotation/failures/{id}/acknowledgeendpoint (RBAC:dashboard:write) writesacknowledged_atandacknowledged_byto the execution row. The dashboard query filters acknowledged rows, keeping the view focused on items that still require attention. The UI exposes a "Mark as reviewed" action from the failure detail panel. - Entra Credential Stuck Watchdog — A new background watchdog (
RecoverStuckEntraCredentials) runs every 5 minutes and resets Entra credentials stuck inrotatingorpending_verificationlifecycle state for more than 30 minutes. This prevents indefinite stalls caused by backend restarts or goroutine cancellations mid-rotation. Each recovery writesstuck_watchdog_recovered_atto the credential row for auditability. - Entra Credential Status —
pending_verification— Theentra_credentials_status_checkconstraint was extended to allow thepending_verificationvalue written byRotateCredentialWithRequestafter every rotation when downstream propagation targets are configured. Without this, any rotation with propagation would produce a constraint violation and leave the credential in an inconsistent state. - CA Account — Assigned Certificates Count — The CA account list and detail responses now include
assigned_certificates_count, the number of active certificates issued via certificate templates bound to that CA account. This gives operators an immediate signal of a CA account's active footprint without an additional query. - Terraform Provider — User, User Role, Keytab, Project Settings, Shared Secret — Five new Terraform resources complete the provider's coverage of the MazeVault user-management and project-configuration surfaces:
mazevault_user(create/read/update/delete of platform users),mazevault_user_role(assign roles to users within an organization),mazevault_keytab(manage Kerberos keytab files attached to a project),mazevault_project_settings(project-scoped configuration knobs), andmazevault_shared_secret(secrets shared across multiple projects).
Improvements¶
- Rotation Problems — Acknowledged Filter — The Rotation Problems page and the platform summary service exclude acknowledged executions from failure counts and lists by default, using the partial index
idx_rotation_executions_unacknowledgedintroduced in migration000170.
Database Migrations¶
000169_entra_credentials_status_pending_verification— Extends theentra_credentials_status_checkconstraint to includepending_verification.000170_rotation_execution_acknowledgement— Addsacknowledged_at TIMESTAMPTZandacknowledged_by UUID REFERENCES userstorotation_executions. Includes partial indexidx_rotation_executions_unacknowledgedcovering only un-acknowledged rows.000171_entra_credential_stuck_watchdog— Addsstuck_watchdog_recovered_at TIMESTAMPTZtoentra_credentials. Adds partial indexidx_entra_creds_stuck_watchdogover(lifecycle_state, updated_at)for the two in-flight states.
Version 1.0.50¶
Release Date: 2026-06-21
New Features¶
- Rotation Config Templates — A new organization-scoped catalog allows operators to record reusable rotation settings (interval, lead days, retention window, max retries, timeout). Managed via five API endpoints under
GET|POST /api/v1/rotation/templatesandGET|PUT|DELETE /api/v1/rotation/templates/{id}with RBAC (rotation:read/rotation:write). A dedicated Terraform resourcemazevault_rotation_templateenables IaC-driven catalog management. Templates are not automatically applied to rotation configurations. The frontend exposes a full CRUD management page at/rotation/templates. Migration000168adds therotation_config_templatestable and atemplate_idforeign key onrotation_configs. - Sync Rule — Bidirectional Mode and Conflict Strategy — The
SyncRuleModalnow exposes configurable sync direction (pull/push/bidirectional) and sync mode (incremental/full_sync) fields. Both attributes are persisted server-side and documented in the new Terraform resourcemazevault_sync_rule. Pull-sync operations now writelast_pulled_at,link_purpose, andexternal_secret_pathintosecret_integration_links(migration000167), enabling thesynced_from_externalstatus badge on secrets that were pulled from an external provider. - Dry-Run for Certificate Rotation — The Certificate Rotation tab now includes a "Dry Run" button alongside the existing "Trigger Rotation Now" action. Dry-run executes the full rotation workflow validation — including post-rotation action preflight and gateway probing — without committing any changes. The
dry_runflag is propagated end-to-end through the API and all rotation steps. - Post-Rotation Action — Gateway Pinning and Environment Override —
PostRotationActionnow accepts an optionalgateway_idfield that pins the action to a specific gateway, bypassing environment-based routing. A companiontarget_environmentfield overrides the environment context used when resolving the target. Both fields are available in the Go SDK (PostRotationActionWF) and in the Terraformmazevault_rotation_workflowresource. - Terraform Provider — Sync Rules and Rotation Templates — Two new Terraform resources cover the full create/read/update/delete lifecycle:
mazevault_sync_rule(sync direction, conflict strategy, key transform, path prefix) andmazevault_rotation_template(interval, lead days, retention, retry policy). Both are registered in the provider and documented indocs/resources/. - Rotation Problems — Failed Executions Detail View — The Rotation Problems page now renders a detailed failed-execution table with per-resource drill-down, a pie-chart distribution by resource kind, and a missing-secrets breakdown. Navigation from the sidebar highlights the section with a warning icon.
Improvements¶
- Distributed Sync Semaphore via Redis —
SyncRuleServicenow uses a Redis-backed distributed lock (SET NX PX) through a newTryAcquireLock/ReleaseLockpair onCacheService. When Redis is unavailable the service falls back to an in-processsync.Maplock. This prevents duplicate concurrent syncs for the same rule in multi-replica deployments. - Dry-Run Guard in All Rotation Steps — All seven built-in rotation steps (password generator, Azure Key Vault, Spring Actuator, agent command, shell script, IIS recycle, Kubernetes secret) now check the
dry_runflag before making any mutating external call and return a preview result instead. - Connection Validation Scope Extended — The
connection_validationrotation step was extended to cover non-database provider types (Azure Key Vault, Kubernetes, LDAP, GitHub, GitLab, generic webhook), ensuring pre-execution connectivity checks are not silently skipped for secrets backed by those integrations. names_onlySecret Rotation Guard — The rotation orchestrator now rejects rotation requests for secrets withstorage_mode = names_onlywith a clear error message, preventing misleading execution records for secrets whose value lifecycle is managed entirely by the external provider.- Secret Sync Status —
synced_from_externalIndicator —GetSecretSyncStatusnow returnssynced_from_externalwhen a secret has been successfully pulled from an external provider. The Secrets tab surfaces this as an informational "Synced from KV" badge. - Compliance Report — Deployment and Sync Coverage Stats —
PasswordPolicyStatsis extended withsecrets_with_deployment_target,secrets_with_external_sync, andsecrets_with_templatecounters. The compliance report service gathers these in a single additional DB pass. - Gateway Task Service — Direct Gateway ID Pinning —
GatewayTaskService.CreateTasknow accepts an optionalGatewayIDthat, when set, skips the routing-service lookup entirely and dispatches the task directly to the named gateway. This supports pinned post-rotation actions without routing ambiguity. - Code Readability — Internal service and model struct fields were reformatted for consistency.
resolveRotationResourceIncidentTargetparameters were simplified, removing redundant intermediate variables.
Bug Fixes¶
- Dashboard Dismiss — TypeScript Type Narrowing — The dismiss handler for actionable rotation items now correctly narrows
item.statusfrom'overdue' | 'failed' | 'running'to the server-accepted'overdue' | 'failed'union before sending the dismiss request, fixing a TypeScript compile error introduced when'running'was added to the item status type. - Rotation Template Routes Missing After Refactor — The five
/api/v1/rotation/templatesroute registrations were inadvertently removed during a code-formatting pass. All five routes have been restored with RBAC middleware (rotation:read/rotation:write). - Swagger Path Drift for Rotation Templates — Swagger
@Routerannotations inhandlers_rotation_templates.goincorrectly used/rotation-templatesinstead of the actual gin route path/rotation/templates. All five annotations were corrected and the OpenAPI spec was regenerated. - Audit Logging Missing on Secret Link Operations —
CreateSecretLinkandDeleteSecretLinkhandlers now emitSECRET_LINK_CREATEDandSECRET_LINK_DELETEDaudit log entries with the correct resource type, ID, and caller IP.
Database Migrations¶
000167_secret_integration_links_pull_tracking— Addslast_pulled_at TIMESTAMPTZ,link_purpose VARCHAR(64), andexternal_secret_path VARCHAR(512)columns tosecret_integration_links. Includes a unique constraintuq_sil_secret_integrationand a partial index for active links.000168_rotation_config_templates— Adds therotation_config_templatestable with full CRUD columns (name, description, org scope, default flag, rotation interval, lead days, retention days, retry policy, timeout). Addstemplate_id UUID REFERENCES rotation_config_templatestorotation_configs.
Version 1.0.49¶
Release Date: 2026-06-20
New Features¶
- Domain Control Validation (DCV) for External CA Orders — External CA providers (DigiCert CertCentral v2, SSLMarket) that require domain ownership proof before issuing a certificate now have full DCV lifecycle support. A new
certificate_dcv_tokenstable (migration 000166) stores per-domain challenge tokens. The backend automatically fetches tokens after order submission, transitions the renewal queue item topending_dcv, and polls every 5 minutes. The frontendDCVStatusPanelcomponent shows per-domain challenge details (DNS TXT record name/value, HTTP file path/content, or approver email) with copy-to-clipboard buttons, a progress bar, and a manual Retry Verification action. New API endpointsGET /api/v1/renewal-queue/{id}/dcvandPOST /api/v1/renewal-queue/{id}/dcv/retryexpose the DCV state with RBAC (certificate:read/certificate:write). - ADCS Pending-Approval — Non-Blocking DCOM Submission — The ADCS DCOM method no longer blocks the HTTP handler goroutine with a 5 × 5 s retry loop when the CA manager has not yet approved a request (ADCS status 5). It now returns
ErrADCSPendingApprovalimmediately; the existingADCSApprovalPollerbackground job handles asynchronous retrieval once the request is approved. - Certificate Request — Advanced Subject DN Fields — The Request Certificate modal now exposes optional Subject DN fields: Organisation (O), Organisational Unit (OU), Locality (L), State/Province (ST), and Country (C). Populated values are sent as a structured
requested_subjectobject in the CSR request payload. - Certificate Request — Key Algorithm Override — For MazeVault-generated key pairs, operators can now override the key algorithm (RSA, ECDSA, Ed25519) and key size directly in the Request Certificate modal. The selection is sent as
requested_key_algorithmandrequested_key_sizein the CSR payload. - Actionable Rotations Dashboard Panel — The Overview dashboard now includes a dedicated "Rotation operations" panel that surfaces overdue and failed rotation resources requiring immediate attention. Each item shows kind, project, and status badge, and supports a one-click Dismiss flow with audit note. Up to five items are shown, prioritized by age (overdue) and recency (failed).
- Dashboard Expiring Certificates — 30-Day Filter — The "Direct actions" section of the Overview dashboard now filters expiring certificates to the next 30 days, making the list immediately actionable instead of showing all future expiries. The section is titled "Expiring certificates (next 30 days)". The
GET /api/v1/dashboard/certificates/expiringendpoint accepts a new optionaldaysquery parameter (1–3650) to scope results; omitting it returns all future-expiring certificates (backward-compatible). - Entra Credential Staged Rotation and Dry-Run — Entra credential rotation now supports staged rotation (
staged_rotation_enabled) with a configurable soak window (soak_window_hours). Both fields are persisted in the rotation resource metadata and round-trip correctly through the rotation config GET/PUT cycle. A dry-run path validates the rotation workflow against the live Entra tenant without applying any changes. - Entra Integration — Instance ID and Protocol Versioning — Entra integrations now carry an instance identifier and a protocol version field, enabling more precise targeting and future compatibility in multi-tenant and delegated execution scenarios.
- Rotation Scheduler — Stuck-Item Recovery — The rotation scheduler now detects resources stuck in a running or approval-pending state beyond a configurable deadline and resets them to a retriable state, preventing silent indefinite stalls. Renewal orchestration also gained explicit coordination logic for resources transitioning through the renewal window.
- Certificate Rotation — Next Due Date Calculation — Certificate rotation due-date logic is now covered by dedicated unit tests. The next due date is computed from effective lead-day policy across certificate, template, and CA-account layers, ensuring consistent renewal window behavior.
Improvements¶
- Dashboard Data Fetching Resilience — Dashboard data fetching now uses
Promise.allSettledinstead ofPromise.all. Individual widget failures (network error, 401, 404) no longer discard data from all other widgets. Each failure is logged via the structured logger for observability. - RBAC Permissions for Rotation Endpoints — Rotation resource read and write permissions are now consistently applied across all new dashboard and rotation endpoints, including archived-resource filtering in service-layer queries.
- Dashboard Service Archived Resource Exclusion — Platform rotation summary and actionable rotation queries now explicitly exclude archived resources, preventing historical data from inflating overdue or failed counts.
Bug Fixes¶
- Entra Rotation Config Edit — Disabled State Regression — Editing an existing Entra credential rotation configuration no longer shows all fields as disabled for non-primary credentials. The GET response now returns
rotation_enabledfrom the stored user preference (metadata.rotation_enabled) instead of from the scheduler gate (resource.Enabled = RotationEnabled && IsPrimary), which was alwaysfalsefor non-primary credentials. - Entra Rotation Config — Staged Fields Not Restored on Edit —
staged_rotation_enabledandsoak_window_hoursare now included in the rotation resource projector metadata and are therefore correctly restored when opening an existing rotation configuration for editing. - Entra Scope Binding — Tenant ID Not Required — Creating an Entra scope binding no longer requires
tenant_idwhen the integration uses managed identity authentication. The backend validation and the frontend wizard were updated to treattenant_idas optional for managed identity flows.
Infrastructure¶
- Step-CA Network Policy — Added network policy rule to allow inbound traffic to Step-CA on port 9000 from within the cluster, unblocking staging ACME issuance flows that route through the internal Step-CA provisioner.
Version 1.0.48¶
Release Date: 2026-06-16
New Features¶
- PFX Compatibility Profile Options — Certificate PFX export now supports selecting a compatibility profile (
legacy/modern) that controls the encryption and MAC algorithms used in the PKCS#12 container.legacytargets OpenSSL 1.x, Java KeyStore tooling, and older Windows endpoints;moderntargets OpenSSL 3.x, .NET 6+, and current Go runtimes.
Improvements¶
- Log Redaction — Original Request URL Preserved — The log redaction middleware now preserves the original
RequestURIon the Gin context before any path rewriting or normalization occurs. This ensures audit and structured log entries reflect the URL the client actually sent, not a post-processing artifact. A regression test covers the URL-preservation contract. - Binary Download — ArrayBuffer and Delayed URL Revocation — Certificate and agent binary downloads now use
arraybufferresponse type and delay object URL revocation until the download has been reliably delivered to the browser, eliminating a race condition on slow connections where the revocation fired before the download completed.
Dependency Updates¶
- form-data and hasown — Updated
form-dataandhasownto their latest patch releases, resolving minor compatibility warnings with current Node.js runtimes.
Version 1.0.47¶
Release Date: 2026-06-14
New Features¶
- Shared Entra Rollout Actions and Readiness Checks — Entra credential rotation now supports ordered rollout actions through the shared rotation platform, including Azure Key Vault, Kubernetes Secrets, agent-managed runtime files, Spring refresh/webhook delivery, and IIS app pool recycle on Windows targets. Dry-run and preflight checks validate the same runtime paths before production execution.
- Per-Certificate Renewal Key Policy — Certificate operators can now choose per certificate whether renewal regenerates a new private key or reuses the existing key material where the provider and custody path allow it. Target processing order is now preserved explicitly in the renewal workflow.
- Stronger Entra Integration Authentication Validation — The integration wizard and backend now validate interactive and background Entra authentication settings together, preventing save-time acceptance of configurations that cannot support background sync, dry-run, or post-rotation execution.
Improvements¶
- Unified Rotation Readiness in the Project Hub — The Project Rotations view now shows inline readiness and preflight state for Entra credentials, certificate renewal resources, and certificate deployment resources, including clearer
manual review requiredsurfacing for rollout targets that cannot be probed automatically. - Role and Contract Alignment for Rotation Operations — RBAC migrations and project-surface permission checks were aligned with the expanded rotation and configuration surfaces, reducing cases where operators could open a screen without the permissions needed to complete the workflow.
- Swagger and Operational Signal Refresh — Generated Swagger output now reflects the updated severity vocabulary and improved host handling, while certificate and database health checks expose stronger diagnostics for rotation readiness and export paths.
- Secret Rotation API Contract Refresh — The secret rotation API and generated Swagger now document the explicit create/edit/delete lifecycle more accurately, including persisted post-rotation actions and the clean reset path after a secret rotation is removed.
Bug Fixes¶
- Entra Lifecycle Cleanup Consistency — Deleting an Entra integration or a locally managed app registration now removes associated Entra credential rotation resources in the same lifecycle operation. Upgrade migration
000155also removes historical orphan rows, and repository reads defensively hide staleentra_credentialentries that predate the cleanup. - Certificate Rotation Defaults on Import — When an imported certificate is eligible for managed renewal, MazeVault now prepares the rotation configuration without silently enabling it. Initial lead days are resolved from the effective certificate, template, and CA-account policy instead of being masked by the model default.
- Rollout Validation and Export Robustness — Validation for
agent_idversus directagent_urlrollout steps is stricter, and certificate export flows now return clearer PFX and private-key failures instead of partially masked errors. - Secret Rotation Delete and Recreate Semantics — Deleting a secret rotation now removes the rotation config, canonical secret rotation resource, and linked rotation integrations without deleting the secret itself. After deletion, secret status surfaces show
Rotation not configured, and reopening the rotation modal stays in create mode until the operator explicitly saves a new configuration.
Version 1.0.46¶
Release Date: 2026-06-09
New Features¶
- External CA Order Poller Baseline — MazeVault added background polling for externally issued certificate orders, allowing asynchronous CA workflows to complete and update the certificate lifecycle without manual tracking.
Notes¶
- Release Note Clarification — The Entra rotation rollout, certificate rotation UI unification, and related readiness and preflight work that had previously been drafted for
v1.0.46landed after the tag and are therefore documented underv1.0.47.
Version 1.0.45¶
Release Date: 2026-06-09
New Features¶
- Rotation Resource Registry and Platform Ownership Expansion — The rotation platform is expanding from certificate-only orchestration into a registry-backed resource model. New control-plane services introduce resource kinds, target registries, and shared ownership for rotation scheduling, making future secret, certificate, and Entra rotation flows converge on the same platform primitives.
- Agent Discovery Policy Bundles and Persistent Config Indexing — Agents now receive backend-driven discovery policy bundles built from active configuration templates. Filesystem discovery persists a local metadata index and reuses cached config and certificate findings across runs, reducing repeated scans while keeping policy-version changes authoritative.
- Configuration Discovery Submission — Agents can now submit configuration discovery findings back to the backend, including classification and rewrite-plan metadata, using the existing discovery result model.
- Certificate Template Code Deduplication and Conflict Resolution — Organization certificate template management now deduplicates template codes and blocks ambiguous conflicts. Upgrade migrations normalize existing duplicates so template routing and issuance remain deterministic.
- System Certificate Classification — Certificates now carry an
is_systemflag for internal mTLS and identity-management material. MazeVault can retain these certificates for platform use while keeping them separate from normal operator-facing inventory. - Integration Groups — Projects now support named integration groups that map logical groupings to integration targets with structured JSONB configuration. Groups can be created, listed, updated, and deleted via the new
/api/v1/projects/{id}/integration-groupsand/api/v1/integration-groups/{id}API endpoints (migration 000152). - Real Slack Incident Notifications — Incident management now dispatches real-time Slack notifications via a configured Incoming Webhook. When an incident is raised on a project with a Slack integration, the platform posts the incident type and resource name to the configured channel.
- GCP Secret Manager and Kubernetes Connectivity Tests — Integration health checks now validate live GCP Secret Manager API access (listing secrets in a given project) and Kubernetes API server reachability using in-cluster or kubeconfig credentials, in addition to the existing provider tests.
- HSM Key Operations — HSM providers (PKCS#11, AWS CloudHSM, GCP Cloud HSM, Azure Managed HSM) now expose full key lifecycle operations:
GetPublicKey(reconstructs RSA/EC PKIX DER from hardware),DeleteKey(destroys all key objects on the device),ListKeys(enumerates all managed key handles), andGetKeyInfo(returns key type, size, and extractable flag). - Vault PKI Full Lifecycle — HashiCorp Vault CA provider now implements the complete CA interface:
RenewCertificate,GetCertificateStatus(checks revocation timestamp),ListIssuedCertificates(enumerates via PKI list endpoint),GetOrderStatus, andCancelOrder(revokes the underlying certificate). - ADCS Deferred Certificate Retrieval — The ADCS (WCCE) provider now fetches certificates that were issued asynchronously by the CA via a SOAP Renew request. Previously pending certificates are retrieved and returned in PEM format once the CA completes issuance.
- Venafi VaaS Full Lifecycle — Venafi CA provider now implements
RenewCertificate,GetOrderStatus(retrieves pick-up status from VaaS), andCancelOrder. - DigiCert Rate Limit Reporting — The DigiCert provider now queries live rate limit headers (
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset) and surfaces them through theGetRateLimitsinterface. - Config Injection with Live Secret Values — Configuration versioning now resolves
${VAULT:<placeholder>}tokens against live MazeVault secret values at snapshot time, so injected config files carry real credentials without storing them in the config version history.
Improvements¶
- Project-Aware Resource Visibility Policies — Azure discovery endpoints now apply
resource_visibility_policyfiltering in the context of the selected project. This keeps Integration Wizard choices aligned with project scope for non-admin operators instead of exposing subscription-wide results. - Configuration Management Auditability — Configuration management flows now record audit-aware rewrite-plan activity so operational changes are traceable alongside the rest of the platform's lifecycle events.
- Generated CSR and Key Custody Metadata — Certificate request flows now carry generated-CSR and private-key custody metadata forward, improving visibility of whether MazeVault owns, reuses, or must preserve external key material in subsequent lifecycle actions.
- Delegated Agent Secret Sync Step — Rotation and execution pipelines now have an explicit agent-side secret synchronization step, improving parity between platform orchestration and what managed agents actually apply downstream.
- Certificate Owner-Surface Navigation — Certificate links from the main dashboard, project rotations, and the certificate inventory now resolve directly to the owning surface. Project-owned certificates open their project detail view, while unassigned inventory opens the Discovered Certificates owner surface via
managed_certificate_id, replacing the legacy duplicate/certificatesflow. - Secret Dashboard Data Consistency — The Secrets Overview tab now uses the shared dashboard API, restoring missing-secret drill-ins and keeping overview counts and decrypted names aligned with the main dashboard data layer.
- Discovered Certificate Lookup Filter — Discovery APIs and generated Swagger documentation now support
managed_certificate_idfiltering, enabling targeted deep links from certificate overview tables to the matching discovered certificate record.
Bug Fixes¶
- Rotation Scheduling Ownership Cutover — Renewal scheduling is moving to the shared rotation platform owner model so follow-up workflows operate on the current certificate resource instead of stale pre-renewal anchors.
- Discovery Project Context Consistency — Integration discovery helpers now consistently pass project context, avoiding empty or over-broad Azure discovery responses when resource visibility filtering is enabled.
- Detect Drift Authentication —
POST /api/v1/secrets/drift/detectnow executes inside the authenticated secrets route group, fixing 401 failures caused by missing auth context on drift-detection requests. - Dashboard Drill-In Regressions — Fixed stale certificate links that still pointed to the removed global certificates page and restored missing-secret links in the Secrets Dashboard overview.
Version 1.0.44¶
Release Date: 2026-05-25
New Features¶
- Certificate Rotation Post-Actions — Certificate rotation now supports explicit post-rotation action chains, including webhooks and other registered post-processing steps, so operators can trigger downstream refresh and rollout workflows after a successful renewal or deployment.
- Delegated Renewal and Rotation Publish Controls — Renewal orchestration gained delegated execution paths, runtime probes, and publish-gate safeguards that better separate readiness validation from side-effecting deployment work.
- Archive Center Lifecycle Enforcement — Archive restore and permanent delete flows are now treated as centralized archive-lifecycle operations with admin-only enforcement across runtime RBAC and role editing.
- Expanded Agent Binary Coverage — MazeVault agent distribution now includes additional ARM64 coverage and stronger build validation for heterogeneous Windows and Linux estates.
Improvements¶
- Discovered Certificate Key Custody Tracking — Adopted discovered certificates now preserve explicit key-custody state, preventing MazeVault from silently taking ownership of private keys during renewal or deployment flows.
- Certificate Issuance and Renewal Robustness — Certificate issuance, CSR handling, and renewal flows now use stronger locking, normalized post-action payloads, and clearer actor attribution across cross-project secret operations.
- CA Account Provider Coverage — CA account and EAB credential handling now covers more provider initialization paths, including Smallstep-specific fallback fields used during account creation and validation.
Bug Fixes¶
- Smallstep CA Account Initialization — Smallstep CA account creation now correctly falls back to credential fields such as
server_urland provisioner metadata instead of failing before contacting the CA. - Rotation Action Contract Alignment — Certificate post-action handling now exposes only action types supported by the certificate rotation executor, avoiding invalid UI selections and mismatched step names.
Version 1.0.43¶
Release Date: 2026-05-11
New Features¶
- Azure Key Vault Managed Identity Support — Azure Key Vault integrations now support Managed Identity and Workload Identity as authentication methods in addition to service principals. When Azure Key Vault is selected in the Integration Wizard, the background sync auth method defaults to
managed_identity. Configure a specific managed identity client ID viaAZURE_MANAGED_IDENTITY_CLIENT_ID, or leave it unset to let the platform resolve the bound identity from the environment (AZURE_FEDERATED_TOKEN_FILE+AZURE_CLIENT_ID+AZURE_TENANT_IDfor workload identity). - Agent Systemd Service Installation — The agent installer script now deploys the MazeVault agent as a proper systemd service. A dedicated
mazevault-agentsystem user is created automatically, and locked-down directories are provisioned (/etc/mazevault,/var/lib/mazevault,/var/log/mazevault) with ownership and permissions (0750). The service is configured with automatic restart on failure. Existing deployments should re-run the deployment script to receive the updated service unit. - Agent Binary Download Endpoint — A new deployment-scoped endpoint
GET /deployments/:id/agent-binaryserves the agent binary for a given deployment. The deployment UUID acts as the authentication token (unguessable 128-bit identifier), consistent with the/scriptand/configendpoints. Legacy agent binary download rewrite rules in the reverse proxy have been removed. - Redis Multi-Endpoint Support — Redis connection handling now supports multiple endpoint addresses for high-availability and fallback setups. Configure the primary endpoint via
REDIS_URLand one or more fallback addresses viaREDIS_FALLBACK_URLS(comma, semicolon, or newline-separated). The client automatically falls back to the next available endpoint on connection failure, and switches to an in-memory fallback if all Redis endpoints are unavailable. - Password Complexity Policy in Organization Settings — Organization Settings now exposes a dedicated Password Complexity Policy editor. Rules are enforced at password change time (minimum length, character class requirements, history depth). On upgrade, organizations are automatically migrated from the legacy
secret_complexity_policyfield.
Improvements¶
- Entra Credential Rotation History — Entra ID credential rotation operations now produce a persistent rotation history record for each event. The history captures the rotation type, old and new key identifiers, workflow and execution IDs, step-by-step progress, final status, error details if applicable, and elapsed duration. This enables full lifecycle traceability for Entra credential rotations.
- RBAC Permission Alignment — Role permissions updated to match the agreed product policy:
secret_manager— gainskeytab:readandconfig:read(KeyTab Management and Configuration Management pages are now accessible)certificate_manager— gainsconfig:read(Configuration Management page is now accessible)auditor—keytab:readremoved (KeyTab Management is no longer visible to auditors; assign explicitkeytab:readwhere audit access to keytabs is required)
- Admin Credential Reference Types Expanded — Database admin credentials now support two additional reference types:
mazevault(credentials stored as MazeVault-managed secrets) andexternal(generic external references). Full set of supported types:internal,mazevault,external,keyvault,aws_sm. - Secret Sync Async Seeding with Status Summary — Sync seed operations now run asynchronously and return immediately with a progress reference and detailed status summary (secrets created, updated, skipped, failed). Blocked seed incidents are now surfaced on the Conflict Resolution page.
- Certificate Issuance Linked to Agent — Certificates issued to a registered agent are now linked to the issuing agent record at issuance time, connecting the certificate lifecycle to the agent in the dashboard and rotation orchestration.
- Security Enhancements — Bootstrap and KeyTab Handlers — KeyTab update and delete handlers now enforce organization ownership checks (IDOR prevention): access to a keytab belonging to a different organization returns 404. The bootstrap password change endpoint is locked after initial bootstrap completes and rejects further calls with 403 Forbidden. A DAST scan workflow has been added to the CI pipeline.
- License Renewal Contact Updated — The license renewal contact email is now
info@mazevault.comacross all notification banners and expiry modals.
Bug Fixes¶
- SSO Provider Modal: Provider ID Preserved on Save — Fixed a bug where saving an existing SSO provider configuration dropped the provider ID, causing duplicate provider creation on subsequent saves.
- Password Complexity Policy Backfill — Organizations that had configured a secret complexity policy via the legacy
secret_complexity_policyfield were incorrectly evaluated as having no password policy, causing false-positive PCI-DSS 8.3 compliance failures. The policy is now automatically propagated to the dedicated password complexity field on upgrade. Additionally, organizations without any complexity policy now receive a secure default policy on upgrade (16-character minimum, all character classes required, 10-entry history, 30-day rotation interval).
Version 1.0.42¶
Release Date: 2026-05-11
New Features¶
- Certificate Metadata Fields — Certificates now support three user-editable metadata fields accessible from the certificate detail view and via
PUT /api/v1/certificates/:id:- Tags — Free-form string labels for grouping and filtering certificates. Tags set at import time are now persisted and remain editable after import. Send an empty array to clear all tags.
- Documentation URL — Optional link (http/https) to external documentation, runbooks, or CMDB entries for the certificate. Maximum 500 characters.
- Notes — Short free-text annotation (maximum 256 characters). Send an empty string to delete the note.
- All metadata field changes are recorded in the audit log.
Improvements¶
- Environment Canonicalization Enforced at Task Creation — Gateway task creation now enforces environment slug canonicalization. All gateway tasks are stored with lowercase environment slugs regardless of caller casing, building on the canonicalization infrastructure introduced in v1.0.41. The
MAZEVAULT_ENV_CANONICAL_ENFORCEvariable (set totrueto fail-close on non-canonical inputs) applies to task creation as of this release.
Version 1.0.41¶
Release Date: 2026-04-26
Improvements¶
- Documentation Sync — Comprehensive documentation update aligned with v1.0.41 codebase. Environment variable reference expanded with five new sections: License/Organization Registration, Orchestrator Mode, ACME DNS-01, KeyTab Management, and Agent Binary Proxy. All existing sections updated with previously missing variables.
- Office 365 Email Variable Corrected — Fixed incorrect variable name
O365_ENABLED→O365_EMAIL_ENABLEDthroughout documentation. Full Office 365 authentication configuration documented (client secret, certificate, and managed identity methods). - KeyTab API Reference — Full API documentation published for all 14 KeyTab management endpoints. See KeyTab API.
- Reports API Reference — Full API documentation published for the Weekly Expiry Reports endpoints. See Reports API.
- Platform Version Sync — All documentation pages updated to reflect current platform version.
Version 1.0.40¶
Release Date: 2026-04-25
New Features¶
- OIDC Nonce Enforcement — New
MAZEVAULT_ENFORCE_OIDC_NONCEflag enables strict nonce validation on OIDC tokens. When set totrue, tokens without a valid nonce claim are rejected, providing protection against token replay attacks. Recommended for all production deployments. - Agent Trust Store Controls — New environment variables
MAZEVAULT_AGENT_INSTALL_CHAIN_TO_TRUSTSTOREandMAZEVAULT_AGENT_TRUST_STORE_PATHcontrol whether the MazeVault agent installs the internal CA certificate chain into the operating system trust store, and allow overriding the default trust store path on Linux.
Improvements¶
- Certificate Rotation Target Sync Status —
GET /api/v1/certificates/:id/targets/:targetId/statusnow returns full per-step result details, making failed target synchronizations easier to diagnose. - Gateway Registration Stability — Improved retry logic for bootstrap token exchange reduces failed registrations caused by transient network issues during first-time gateway setup.
- OCSP URL Validation —
OCSP_URLbackend variable now validates URL format at startup to prevent misconfiguration from silently causing OCSP failures.
Bug Fixes¶
- Corrected
AGENT_VERSION=latestresolution to always fetch the highest tagged release version rather than the most recent commit. - Fixed display overlap in the certificate import modal under Orchestrator Mode when both keytab and private key sections were visible simultaneously.
Version 1.0.39¶
Release Date: 2026-04-22
New Features¶
- Agent Binary Distribution Control — New configuration variables provide granular control over how agent updates are distributed across the fleet.
AGENT_ROLLOUT_PERCENTAGElimits what percentage of agents receive update notifications (0–100), enabling staged rollouts.AGENT_MAX_CONCURRENT_DOWNLOADScaps parallel binary download streams to prevent network saturation. - Agent Binary Proxy — MazeVault can now proxy agent binary downloads from a private GitHub release repository, removing the requirement for agent hosts to reach the public GitHub Releases endpoint directly. Configure via
AGENT_BINARY_GITHUB_TOKEN,AGENT_BINARY_CACHE_DIR,AGENT_DOWNLOAD_BASE_URL, andAGENT_VERSION. - Primary Backend Environment Seeding — New
MAZEVAULT_PRIMARY_ENVIRONMENTSvariable pre-seeds the list of environments served directly by the primary backend on first startup, simplifying initial deployment configuration of multi-environment setups.
Improvements¶
- KeyTab Dashboard Refresh — Fixed cipher compliance breakdown chart not updating after importing a keytab with deprecated ciphers.
- Weekly Report Multi-Channel Reliability — Resolved a scheduling race condition that could silently drop one delivery channel when multiple channels were all enabled simultaneously.
Bug Fixes¶
- Fixed gateway heartbeat timestamp not updating correctly following a network partition recovery.
Version 1.0.38¶
Release Date: 2026-04-19
New Features¶
- KeyTab Management — Full Kerberos Lifecycle — Enterprise-grade Kerberos KeyTab management with complete lifecycle support. Import, discover, and manage keytab files across your infrastructure. Key capabilities include:
- Import & Parse — Import MIT Kerberos v2 keytab binary files with automatic extraction of principals, realms, key version numbers (KVNO), and encryption types. Supports base64-encoded upload.
- Agent Discovery — Agents automatically discover
.keytabfiles on managed hosts, reporting file path, permissions, owner, and encryption type fingerprint. Discovered keytabs can be imported into managed inventory with a single action. - Cipher Policy Enforcement — Define organization-level cipher policies specifying allowed and deprecated Kerberos encryption types. Three enforcement modes:
audit(report only),warn(allow with warning),block(prevent non-compliant keytabs). Default policy blocks legacy ciphers (DES, RC4-HMAC) while allowing modern AES and Camellia ciphers. - Version History — All keytab updates create immutable version records with change reason tracking for full audit compliance.
- Dashboard & Analytics — Dedicated KeyTab dashboard showing total/active/expired counts, cipher compliance breakdown (compliant/warning/critical), expiry forecasts, and cipher type distribution.
- Orchestrator Mode Support — In Orchestrator Mode, keytab binary data is offloaded to an external provider; only metadata is stored locally.
- Weekly Expiry Report — Automated weekly reports showing certificates and secrets expiring within 60 days, delivered to multiple channels simultaneously:
- Email — HTML-formatted report to configured recipient list
- Slack / Microsoft Teams — Webhook-based notifications with expiry summaries
- JIRA — Automatic issue creation with expiry details for tracking
- Generic Webhook — HTTP POST with full report payload for custom integrations
- Reports can be previewed before sending and triggered manually on demand.
- Local Gateway Registration — The primary backend can now register itself as a local gateway, enabling unified gateway management UI for both local and remote gateways. A unique constraint ensures only one local gateway per deployment.
Improvements¶
- Gateway Multi-Environment Support — Gateways can now serve multiple environments simultaneously, removing the previous one-gateway-per-environment restriction.
- Report RBAC Permissions — New
report:readandreport:writepermissions provide fine-grained access control for the reporting system. All standard roles (User, Certificate Manager, Secret Manager, Auditor) receivereport:read; Admin and Project Admin additionally receivereport:write. - KeyTab RBAC Permissions — New
keytab:read,keytab:write,keytab:delete, andkeytab:adminpermissions control access to keytab management. Standard users and auditors receive read access; operators and organization admins receive write and delete; organization admins additionally receive admin access for policy management.
Bug Fixes¶
- Entra Sync Rule Cleanup — Removed orphaned sync rules left behind by deleted integrations, and cleaned up duplicate sync rules for
entra_idprovider type (now handled by the dedicated Entra Sync Scheduler). Fixes recurring "sync failed for rule" errors in production environments.
Version 1.0.37¶
Release Date: 2026-04-16
Improvements¶
- Gateway Task Payload Encryption — Sensitive task payloads exchanged between the primary backend and gateways are now encrypted at rest in the database. The
payload_encryptedflag on gateway tasks ensures that JSONB payloads containing credentials and private keys are protected even if database access is compromised. - Write Queue Exponential Backoff — Multi-datacenter write queue now tracks the timestamp of each retry attempt, enabling proper exponential backoff calculation for failed synchronization operations. This improves reliability and reduces unnecessary load on remote gateways during connectivity disruptions.
Security Updates¶
- Gateway Payload At-Rest Encryption — Task results and payloads in the gateway task queue are now encrypted before database storage, closing a potential data exposure vector in multi-datacenter deployments.
Version 1.0.36¶
Release Date: 2026-04-15
New Features¶
- KeyTab Database Schema — New database tables for keytab management:
keytabs(encrypted keytab storage with cipher compliance tracking),keytab_versions(immutable version history),keytab_cipher_policies(organization-level cipher enforcement), anddiscovered_keytabs(agent discovery results with stale detection). - KeyTab RBAC Permissions — New permission set (
keytab:read,keytab:write,keytab:delete,keytab:admin) assigned to appropriate system roles for keytab lifecycle management.
Improvements¶
- Gateway API Token Enhancement — Improved gateway authentication with dedicated API tokens and bootstrap provisioning support.
- Agent KeyTab Discovery — Agents can now discover Kerberos keytab files on managed hosts and report findings including file path, permissions, owner, encryption types, and SHA-256 fingerprint.
Version 1.0.35¶
Release Date: 2026-04-14
Bug Fixes¶
- PEM Import — Private Key Preservation — Fixed a critical issue where importing a PEM file containing a certificate chain and a private key would silently discard the private key. The system correctly detected the key during file preview but lost it during the actual import, causing subsequent PFX/JKS exports to fail. The PEM bundle parser now correctly extracts PKCS#8, RSA, and EC private key blocks.
- Certificate Import — Project Name in Error Messages — When importing a certificate that already exists, the error message now includes the project name where the duplicate resides (e.g., "certificate already exists … project=MyProject"), making it easier to identify conflicts.
Improvements¶
- Private Key Visibility in UI — Certificates now display their private key status across all views:
- Certificate lists show a green shield icon when a private key is stored.
- The certificate dashboard shows a green key icon next to certificates with private keys.
- The certificate detail modal displays a chip indicating whether the key is stored locally, externally, or not available.
Version 1.0.34¶
Release Date: 2026-04-10
New Features¶
- Identity Provider Group Discovery — New API endpoint
GET /identity-providers/{id}/groupsfetches groups directly from the configured identity provider (Entra ID via Microsoft Graph, LDAP via directory search). Supports search filtering by group display name for easy role mapping. - Identity Provider Test Coverage — Added comprehensive unit test coverage for identity provider CRUD operations, test-connection flow, and group discovery endpoints.
Improvements¶
- JKS Export — Pure Go Implementation — Replaced the external
keytool(JDK) dependency with a native Go implementation usingkeystore-go/v4. JKS export now works in any environment without requiring a Java runtime, includes the full certificate chain, and has comprehensive test coverage. - Gateway API Token Authentication — New
gateway_api_tokenstable and middleware for gateway-to-backend API authentication. Gateways can now authenticate using dedicated API tokens with automatic bootstrap provisioning. - Gateway Write Queue — Added
gateway_write_queuetable for buffering write operations from gateways, enabling reliable data synchronization in multi-datacenter deployments. - Gateway Bootstrap Hardening — Improved gateway bootstrap flow with enhanced validation, Azure SQL connectivity checks, and more reliable initial registration.
- Azure Test Environment Terraform — New Terraform configuration for automated Azure test environment provisioning, including Entra ID enterprise apps, Key Vaults, and Azure SQL.
Security Updates¶
- Gateway Middleware Authentication — New dedicated middleware validates gateway API tokens with proper scope checks and request context propagation.
Version 1.0.33¶
Release Date: 2026-04-09
New Features¶
- Azure Permissions Check Endpoints — Added new Azure access validation APIs for permissions and resource visibility:
POST /api/v1/admin/azure/mi-permissions-checkGET /api/v1/azure/user-permissions-summaryGET /api/v1/azure/subscriptions/{subscriptionId}/sql-servers- Managed Identity Permissions Validation — New managed identity check flow validates access across configured Azure integrations and returns per-integration status results.
- User Permissions Summary — Added a consolidated subscription-level overview of Azure resources visible to the authenticated user, including Key Vault and SQL server discovery.
Improvements¶
- RBAC Integration for Azure Permission Checks — Azure permissions endpoints are now protected by MazeVault RBAC with
integration:readandintegration:writeguards. - Swagger Schema Coverage — OpenAPI definitions now include the Azure permissions check response models (
MIPermissionsCheckResponse,MICheckResult) for accurate API client generation.
Security Updates¶
- Role Permission Alignment — Migration
000109_add_audit_settings_permissionsaddsaudit:readandproject:writepermissions tocertificate_managerandsecret_managerroles for consistent access control behavior.
Version 1.0.32¶
Release Date: 2026-04-08
New Features¶
- Azure Managed HSM Integration — Full support for key storage and manipulation in Azure Managed HSM with automatic certificate updates and key rotation. All private key operations occur in the HSM with metadata returned to the database.
- Organization-Level Password Policy — Define password enforcement rules (minimum length, complexity, expiry) for all organization users. Rules are enforced at password creation and change with legacy integration compatibility.
Improvements¶
- CRDT Sync Performance — Optimized conflict resolution for datasets >100k records, 40% speed improvement on multi-DC setups.
- Extended Audit Logs — Comprehensive recording of all password, certificate, and administrative operations.
Bug Fixes¶
- Fixed cache invalidation timing in cluster deployments.
- Resolved sync failures with large CSR transactions.
Version 1.0.31¶
Release Date: 2026-04-07
New Features¶
- Orchestrator Mode — External Key Storage — MazeVault can now run in a mode where all private keys and secrets are stored exclusively in external key vaults (Azure Key Vault, AWS Secrets Manager, HashiCorp Vault). Local database contains only metadata.
- License Compliance Tracking — Dashboard displays license status in real-time, including used licenses, upcoming expirations, and warning states.
Improvements¶
- Standard → Orchestrator Mode Migration — New CLI commands for safely migrating existing Standard mode systems to Orchestrator mode.
- Orchestrator Mode UI — Toggle in Onboarding Wizard and organization settings.
Bug Fixes¶
- Fixed selective certificate copying in Orchestrator mode.
Version 1.0.30¶
Release Date: 2026-04-07
New Features¶
- ACME Server — Full RFC 8555 Implementation — MazeVault now acts as a fully compliant ACME certificate authority. Any standard ACME client (cert-manager, Certbot, acme.sh, Kubernetes) can obtain and renew certificates directly from MazeVault without manual intervention. Supported challenge types: HTTP-01, DNS-01, TLS-ALPN-01.
- External Account Binding (EAB) — Restrict ACME account registration to authorized clients using pre-shared EAB credentials (HMAC-based). Prevents unauthorized certificate issuance from unknown ACME clients.
- Sync Dashboard — New dashboard section showing real-time synchronization status: configuration overview, active conflicts, and sync failures with per-item resolution guidance.
- Sync Read Permission — New
sync:readpermission grants project members, auditors, and role holders access to sync status endpoints without requiring elevated privileges.
Improvements¶
- ACME Authorization Nonce Hardening — Dedicated nonce table (
acme_server_nonces) with TTL-based expiry ensures strict replay-nonce protection per RFC 8555 §6.5. - ACME Challenge Token Indexing — Challenge tokens now use a dedicated indexed column for O(1) validation lookups instead of JSON scanning, improving throughput under high ACME request volume.
- RBAC — Sync Permissions Aligned —
project_admin,certificate_manager,secret_manager,user, andauditorroles now includesync:readfor consistent access to sync dashboard endpoints.
Bug Fixes¶
- Fixed race condition in ACME order state transitions during concurrent finalize requests.
- Resolved ACME authz table creation ordering issue (migration idempotency).
Version 1.0.29¶
Release Date: 2026-04-06
New Features¶
- Configuration Management Interface — New multi-tab UI for lifecycle management of configuration files: discover YAML/JSON/INI files across environments, stage drafts, and promote configurations to production. Provides visibility into discovered vs. managed configuration counts.
- Certificate Rotation Polymorphic Config — Rotation executions now support both secret and certificate rotation configs in a unified model. The
config_typefield distinguishes between the two, eliminating separate workflow tables. - Rotation Settings Source Tracking — Each certificate now records whether its renewal settings originate from a project template (
template) or were manually configured (manual), providing clear audit attribution for rotation behavior.
Improvements¶
- Organization Scoping for Certificate Requests — Certificate signing requests (CSRs) are now scoped to the originating organization. The
organization_idfield is backfilled from project associations, preventing cross-organization CSR data leakage. - ACME Server Authorization Tables — Database schema for the ACME server protocol (authorization objects and nonce tables) was provisioned in preparation for the v1.0.30 ACME server release.
- Rotation Workflow Cleanup — Removed orphaned
rotation_workflowsandrotation_step_executionstables that were superseded by the unified rotation execution model.
Bug Fixes¶
- Fixed
rotation_configs.next_rotationcolumn rename tonext_rotation_at— scheduler queries now use the correct column name. - Resolved foreign key constraint on
rotation_executions.config_idthat prevented polymorphic rotation config references.
Version 1.0.28¶
Release Date: 2026-04-05
New Features¶
- Secret Naming Policies — Define organization-wide naming conventions for secrets using regex-based rules with three enforcement levels:
block(prevent creation),warn(allow with warning), anddisabled(informational). Policies are managed as configuration templates and validated in real-time on secret creation. - Naming Compliance Dashboard — New tab in the Secrets Dashboard shows a policy violation heatmap, per-rule compliance rates, and auto-generated rule suggestions based on existing secret naming patterns.
- Consistency Framework — Create consistency groups to verify that specified secrets exist across all required environments. The
POST /projects/{id}/consistency/groupsendpoint and dashboard tab surface missing values and environment gaps, withresolve-warningsupport for documented exceptions. - Database Security Defaults — Organizations can now configure per-environment TLS/encryption baselines for database integrations. Production environments default to strict TLS (verify-full, encrypt, TCPS); non-production environments use permissive defaults. Supported providers: Oracle, MSSQL, PostgreSQL, MongoDB, MySQL.
- Enhanced Shared Secrets — Shared secrets now support optional passphrase protection (bcrypt),
recipient_emailfor intent tracking, automatic content-type tagging (secretorcertificate), and rotation source attribution (source_type,source_id) for automated post-rotation distribution.
Security Updates¶
- Consistency RBAC Permissions — New
consistency:readandconsistency:writepermissions control access to consistency groups and warning resolution. Assigned toproject_admin,certificate_manager,secret_manager,user, andauditorroles. - Auditor Role Refinement — The
auditorrole no longer has access to the deployment dashboard or general dashboard views, focusing the role strictly on audit logs, user management, gateway status, and agent status — reducing the attack surface of read-only accounts.
Bug Fixes¶
- Fixed secret naming policy storage: policies are now persisted in
config_management_templatesinstead of the deprecatedorganizations.secret_complexity_policyJSONB column.
Version 1.0.27¶
Release Date: 2026-04-04
New Features¶
- New Roles: Certificate Manager & Secret Manager — Two new purpose-built roles provide fine-grained access control without granting cross-domain visibility:
certificate_manager— Full lifecycle management for certificates, CA accounts, templates, discovery, and deployment. No access to secrets.secret_manager— Full lifecycle management for secrets, rotation, deployment, and integrations. No access to certificates.- SSO Authorization Code Pattern — Access tokens are no longer passed via URL query parameters on SSO callback. The callback now delivers a short-lived opaque code (
sso_code, 60-second TTL) that the frontend exchanges for tokens viaPOST /auth/sso/exchange. This eliminates token exposure in browser history, server access logs, andRefererheaders. Applies to Entra ID, GitHub, and GitLab SSO providers. - Entra Group Mapping Consolidation — Entra ID group-to-role mappings are now stored in the unified
group_role_mappingstable with asourcecolumn (localorentra). This enables consistent group management across local LDAP groups and Entra ID cloud groups from a single interface.
Security Updates¶
- OIDC Nonce Validation — OAuth2 state now carries a server-generated nonce validated at token exchange. Prevents CSRF/token-hijacking via cross-site OAuth state substitution.
- Deprecated Roles Removed — Legacy roles (
operator,developer,org_admin,secret_editor,secret_viewer,certificate_admin,system_admin) have been removed. Existing users with these roles were automatically migrated:operator→project_admin,developer→user. Integrations using deprecated role names in API calls must be updated. - User Role Data Integrity — Fixed zero-UUID primary key corruption in the
user_rolestable caused by a missingBeforeCreatehook. A composite unique index was added to prevent duplicate role assignments. Affected rows were deduplicated during migration. - Soft-Deleted User Email Index — The email uniqueness constraint is now a partial index (
WHERE deleted_at IS NULL). Soft-deleted users no longer block new account creation or SSO registration with the same email address.
Bug Fixes¶
- Fixed Entra group mapping duplication after SSO re-authentication.
- Resolved role assignment failures for users created via LDAP group sync.
Version 1.0.26¶
Release Date: 2026-04-03
New Features¶
- PFX/PKCS#12 Import Improvements — Enhanced PFX certificate import with improved parsing and validation
- Certificate Template Fixes — Resolved template configuration issues affecting certificate enrollment workflows
- Role Mapping Modifications — Updated group-to-role mapping logic for improved SSO integration
- Audit Log Enhancements — Extended audit logging with additional event types and improved traceability
Security Updates¶
- Comprehensive Vulnerability Remediation — Resolved 18 out of 24 identified vulnerabilities across all platform components through systematic dependency scanning and updates
- SAML Signature Bypass Fix (CRITICAL) — Fixed critical SAML XML signature bypass vulnerability in SSO authentication flow (
goxmldsigv1.3.0 → v1.6.0) - HTTP/2 CONTINUATION Flood Fix (CRITICAL) — Resolved actively exploitable HTTP/2 denial-of-service vulnerability in Kubernetes Operator (
golang.org/x/netv0.19.0 → v0.52.0) - gRPC Authorization Bypass Fix — Fixed gRPC authorization bypass via missing leading slash in path (
google.golang.org/grpc→ v1.80.0) - JOSE/JWE Denial-of-Service Fixes — Resolved 3 separate DoS vulnerabilities in JSON Web Encryption handling (
go-jose/v3v3.0.0 → v3.0.4) - Node.js SDK Critical Fix — Eliminated 8 critical Handlebars.js advisories including JavaScript injection and prototype pollution
- CI/CD Security Hardening — Pinned Trivy security scanner to specific version (supply chain protection), enabled security scanning on all CI events
Improvements¶
- Kubernetes Operator Overhaul — Major dependency update to
controller-runtimev0.22.5 andk8s.io/*v0.34.3 with code quality improvements including extracted reconciliation methods, configurable refresh intervals, proper watch propagation, and structured logging - Terraform Provider Fix — Fixed compilation error and updated all dependencies to latest stable versions (
terraform-plugin-frameworkv1.19.0,grpcv1.80.0) - Go SDK Enhancement — Added
Environmentfield to Project model for improved project management - Docker Image Hardening — Pinned OCSP Responder base image to
alpine:3.21(reproducible builds), switched Frontend tonpm cifor deterministic dependency installation - Dependency Alignment — Aligned
golang.org/x/crypto,golang.org/x/net, and other standard library packages across all 7 Go modules to latest stable versions
Version 1.0.25¶
Release Date: 2026-04-01
New Features¶
- Swagger API Documentation Overhaul — Comprehensive regeneration of Swagger/OpenAPI documentation with complete endpoint coverage, improved schema definitions, and accurate request/response examples
- Entra ID SSO Environment Configuration — New environment variables for Entra ID SSO and Azure Managed Identity configuration in
.env.examplefor streamlined deployment setup
Improvements¶
- LDAP & OAuth Provider Configuration — Enhanced SSO provider setup with improved LDAP bind DN handling and OAuth2 flow configuration
- Email Status Endpoint — New
GET /api/v1/system/email-statusendpoint for monitoring email notification delivery status - Certificate Rotation Handlers — New API handlers for certificate rotation execution and status tracking
- Agent Integration Enhancements — Improved agent discovery and integration handlers with better error reporting
- SSH Key Management — Extended SSH key service with improved import and rotation capabilities
Security Updates¶
- Updated authentication service with enhanced token validation and session management
- Improved Entra ID Graph client with additional security headers
Version 1.0.24¶
Release Date: 2026-03-30
Bug Fixes¶
- Entra ID SSO Fix — Resolved critical Entra ID SSO authentication issue affecting login flow and token refresh
- Code Cleanup — Removed deprecated handler code and unused Entra mapping endpoints for cleaner codebase
Improvements¶
- Updated schema models with additional field definitions for improved data integrity
Version 1.0.23¶
Release Date: 2026-03-30
Improvements¶
- Certificate Templates and Expiry Management — Enhanced certificate template configuration with improved expiry tracking, scheduler optimizations, and better CA integration status indicators
- Certificate Import Validation — Improved certificate import service with stricter chain validation and better error messages
- SSLmarket CA Sync — Extended SSLmarket CA provider with improved product synchronization and certificate status tracking
- Extended Logging — Enhanced logging across certificate services for better troubleshooting and audit trail
Bug Fixes¶
- Fixed certificate status calculation in X.509 utility functions
- Resolved certificate dashboard display issues for expiring certificates
- Fixed certificate edit modal preserving incorrect values on save
Version 1.0.22¶
Release Date: 2026-03-30
New Features¶
- Multi-Gateway Environment Support — New database migration and service layer for multi-gateway deployments with environment-specific gateway configuration, health monitoring, and task execution
- Gateway Health Monitor — Real-time gateway health monitoring service with heartbeat tracking, automatic failover detection, and Prometheus metrics
- Gateway Routing Service — Intelligent request routing across multiple gateway instances with load balancing and environment awareness
- Gateway Task Executor — Distributed task execution framework for gateway operations with retry logic and status tracking
- Identity Provider Management — New API handlers for identity provider configuration and management
Improvements¶
- Cipher Key Resolver Hardening — Comprehensive test coverage for cipher key resolution with 715+ lines of new tests eliminating dual storage inconsistencies
- Database Health Checks — Updated expected tables and columns for new gateway-related database schema
- Integration Wizard — New multi-step integration wizard UI for configuring CA providers, secret managers, and external integrations
- Key Derivation Fix — Resolved key derivation issue affecting encryption operations
Security Updates¶
- Eliminated cipher key dual storage vulnerability via migration
000089 - Enhanced authentication service with improved session handling
Bug Fixes¶
- Fixed test failures in certificate orchestrator and configuration management services
- Resolved EntraID SSO redirect issue on certain browser configurations
Version 1.0.21¶
Release Date: 2026-03-26
New Features¶
- Azure Resource Discovery — New API handlers for Azure cloud resource discovery with Key Vault, certificate, and secret enumeration
- Integration Wizard UI — Multi-step wizard for configuring integrations with CA providers and secret managers, including type selection, provider configuration, and review steps
Improvements¶
- CA Account Service — Enhanced CA account management with improved error handling and status tracking
- Model Schema Updates — Updated data models across SSH keys, MFA, OAuth, CRL, and zero-trust modules for improved consistency and validation
- Test Coverage — Expanded test coverage for integration service providers, key offload service, and secret service offload operations
Bug Fixes¶
- Fixed certificate audit event model inconsistency
- Resolved discovered certificate model field alignment issues
Version 1.0.20¶
Release Date: 2026-03-23
New Features¶
- Office365 OAuth2 Email Notifications — Send email notifications via Microsoft Graph API using OAuth2 client credentials flow instead of legacy SMTP; supports 3 authentication methods (client secret, certificate, managed identity); reuses existing Entra ID infrastructure with connection caching and retry logic; transparent replacement — all 6 email trigger points (expiry alerts, incidents, weekly reports, rotation failures, discovery summaries, test notifications) work automatically; new
GET /api/v1/system/email-statusendpoint and frontend status indicator in System Outputs → Notifications tab - SmallStep CA Provider — Integration with open-source step-ca as a Certificate Authority backend supporting JWK, X5C, and OIDC provisioners; mTLS authentication, certificate signing, renewal, revocation, and CRL signing with root fingerprint verification; ideal for zero-trust short-lived certificate architectures
- Multi-Target Certificate Rotation — Deploy certificates to 5 destination types: Secret Managers (Azure Key Vault, AWS Secrets Manager, HashiCorp Vault), Kubernetes Secrets (TLS/Opaque), Agent Keystores (JKS, PKCS12, Windows), Agent Files (PEM), and Database Wallets (Oracle OCI); content mode selection (public only, public+chain, full chain with key, key only), format auto-detection, retry policies with configurable attempts and delays, and post-install command execution
- Enterprise Entra ID Credential Lifecycle — Complete lifecycle management with states (created, active, expiring, expired, revoked, grace period), configurable grace periods (default 30 days), rotation history tracking with old/new key IDs and workflow tracing, expiry monitoring dashboard, idempotency protection against duplicate rotations, and sync conflict resolution for local vs. remote state
- Compliance Report Viewer — Generate and view compliance reports with template-based formatting, organization-wide certificate compliance analysis, and exportable report output
- Rotation Execution History — Detailed per-certificate rotation history with execution timestamps, status tracking (success/failed/pending), and target-level sync status visualization
- Certificate Lifecycle Phase Tracking — New lifecycle phases (stable, renewing, rotating, revoking) prevent duplicate CA requests during in-flight operations; orthogonal to certificate status, ensuring certificates remain valid during phase transitions
Improvements¶
- Audit Stream Destinations — New Elasticsearch destination with index template management, cluster mode and CosmosDB support; new Syslog destination with TCP/UDP transport, CEF and Syslog format support; enhanced log stream service with destination-specific configuration validation
- LDAP Authentication Improvements — Enhanced LDAP service with improved bind DN handling, group membership resolution, schema configuration flexibility, and better error diagnostics for connection failures
- Notification Scheduler Redesign — Improved scheduling logic for certificate expiry notifications with batching support to reduce alert fatigue, JIRA integration for incident ticket creation, and email notification enhancements
- Weekly Expiry Report Service — Redesigned report generation with recipient management, customizable report content, and improved delivery reliability
- Project Template Enhancements — Extended template configuration with naming convention integration, advanced default settings, and improved template-to-project application workflow
- Naming Convention Service — Extended naming convention engine with additional pattern support, validation rules, and convention-to-template linking for automated enforcement
- Prometheus Metrics — New histogram and counter metrics for certificate rotation, compliance reporting, and audit stream performance monitoring
- CI/CD Pipeline — New GitHub Actions workflow for automated build, test, and deployment
- SSO Provider Modal — Added LDAP provider configuration with server, bind DN, and schema settings directly from the SSO configuration interface
- WebLogic Deploy Rotation Step — New rotation step type for Oracle WebLogic Server keystore deployment with automated domain configuration updates
Security Updates¶
- Entra ID credential rotation with full audit trail — every rotation recorded with actor, timestamp, old/new key IDs, and execution status
- SmallStep CA operations logged to audit stream with complete request/response metadata
- Certificate lifecycle phase prevents concurrent CA operations, eliminating race conditions in renewal and rotation workflows
- Entra sync conflict detection with automatic tracking of local vs. remote state discrepancies
Version 1.0.19¶
Release Date: 2026-03-20
New Features¶
- Azure Gateway Deployment — Multi-region Azure Gateway infrastructure with Terraform modules for AKS, Key Vault, PostgreSQL, Redis, networking, monitoring, and identity management; Helm chart values for gateway configuration; Azure DevOps CI/CD pipeline for automated deployment
- Key Vault RBAC Service — Granular role-based access control for Azure Key Vault operations with per-secret and per-certificate permission management
- Key Vault Watch Connector — Real-time synchronization between MazeVault and Azure Key Vault with change detection and automatic secret updates
- Naming Convention Engine — Domain-specific naming rules with wildcard pattern matching, priority ordering, and template-level enforcement for consistent resource naming across projects
- Dashboard Reports Tab — Redesigned reporting dashboard with certificate overview statistics, interactive charts, and exportable report data
- Node.js SDK — Official MazeVault SDK for Node.js with TypeScript definitions, supporting authentication (SRP), organizations, projects, and secrets management
Improvements¶
- Audit Log Project Scoping — Audit events now include project association for efficient per-project filtering and compliance reporting; existing events backfilled from entity relationships
- Orchestrator Storage Mode Fix — Normalized inconsistent storage mode values for Orchestrator Mode deployments, resolving constraint violations
- Entra Group Mappings — Improved group-to-role mapping reliability with better error handling and UI feedback
- Config Encryption Hardening — Enhanced configuration encryption service with additional test coverage and improved error handling for edge cases
- Certificate Import Validation — Improved certificate import service with stricter chain validation
- Go SDK Updates — Updated project and model definitions for consistency with latest API
- Python SDK Updates — Model alignment with latest API schema
Bug Fixes¶
- Fixed environment creation for unused projects being triggered unnecessarily
- Resolved Entra ID SSO login redirect issue on certain browser configurations
- Fixed project template modal not preserving environment associations on save
Version 1.0.18¶
Release Date: 2026-03-14
Improvements¶
- Customer Documentation Updated — Comprehensive ACME certificate automation guide with step-by-step Kubernetes setup, cert-manager ClusterIssuer examples, ACME profile routing, troubleshooting, and complete end-to-end YAML examples; updated Certificates API reference with ACME endpoints and EAB management; release notes reformatted to correct 1.0.x versioning scheme
- Azure Entra ID Integration Improved — Enhanced token refresh handling, improved group-to-role mapping reliability, faster SSO login flow with reduced redirect latency, and better error messages for misconfigured tenant settings
Version 1.0.17¶
Release Date: 2026-03-14
New Features¶
- ACME Server (RFC 8555) — MazeVault now acts as a full ACME Certificate Authority, enabling automated certificate issuance via cert-manager and other ACME clients
- External Account Binding (EAB) — Secure cluster registration with one-time-use credentials linking ACME clients to organizations and projects
- ACME Profile Routing — Map cert-manager profile names to MazeVault Certificate Templates for automatic CA backend selection (cert-manager v1.18+)
- Domain Rule Engine — Configure domain-to-template routing rules with wildcard pattern matching and priority ordering
- Auto-Approve for Internal Domains — Certificates for
.local,.internal,.lan, and.corpdomains are issued instantly without HTTP-01 challenge - ADCS Bridge via ACME — Issue certificates from Microsoft Active Directory Certificate Services through standard ACME protocol
- ADCS Agent Improvements — DCOM retry logic for pending certificate requests with configurable intervals
- EAB Credential Management UI — Generate, list, and revoke EAB credentials from the web interface with cert-manager YAML examples
Improvements¶
- ACME directory endpoint with meta profiles for automated client discovery
- JWS middleware with ES256 and RS256 signature verification
- Nonce-based replay protection per RFC 8555 §6.5
- Full PEM certificate chain delivery for ACME clients
- EAB credentials table with status tracking (Available / Used / Revoked)
- One-click copy for ACME directory URL and generated credentials
Security Updates¶
- EAB HMAC keys encrypted at rest with AES-256-GCM
- EAB credentials are single-use and support expiration and revocation
- JWK Thumbprint verification (RFC 7638) for account binding
- All ACME operations recorded in audit log
Version 1.0.16¶
Release Date: 2026-02-28
Improvements¶
- Organization settings redesign with tabbed navigation
- Certificate Authority account cards with sync status indicators
- Improved CA product discovery and sync trigger via UI
- Agent heartbeat interval optimization for large fleets
- Database connection pool tuning for high-concurrency deployments
Bug Fixes¶
- Fixed certificate chain validation for intermediate CA certificates
- Resolved race condition in concurrent secret rotation scheduling
- Fixed OCSP responder cache invalidation on certificate revocation
Version 1.0.15¶
Release Date: 2026-02-14
Improvements¶
- PFX/PKCS#12 import with configurable key storage (software / HSM)
- Certificate template override support for CA account-level defaults
- Improved agent reconnection logic after network interruptions
- Enhanced audit log filtering by event type and date range
Bug Fixes¶
- Fixed certificate export with chain for cross-signed intermediates
- Resolved project template settings not persisting after save
- Fixed SSH key discovery deduplication for rotated keys
Version 1.0.14¶
Release Date: 2026-01-31
Improvements¶
- SSH key management enhancements — authorized key tracking and discovery
- Rotation trigger improvements with foreign key constraint handling
- Secret sharing post-rotation with automatic re-encryption
- Improved error messages for agent proxy authentication failures
Bug Fixes¶
- Fixed rotation scheduler timezone handling for non-UTC installations
- Resolved dashboard certificate count discrepancy after bulk import
- Fixed API token expiration check for service identities
Version 1.0.13¶
Release Date: 2026-01-24
Improvements¶
- React import modernization — tree-shaking optimized MUI imports
- Frontend build size reduction (~15% smaller bundle)
- Improved certificate search with wildcard SAN matching
- Enhanced monitoring Prometheus metrics with histogram buckets
Bug Fixes¶
- Fixed RBAC permission check for nested project environments
- Resolved Terraform export formatting for complex secret values
- Fixed health check endpoint returning stale Redis status
Version 1.0.12¶
Release Date: 2026-01-17
Improvements¶
- Trivy container image scanning integration in CI/CD pipeline
- Security vulnerability remediation for dependency chain
- Improved TLS cipher suite configuration with Mozilla Intermediate profile
- Enhanced rate limiting with sliding window algorithm
Bug Fixes¶
- Fixed certificate renewal scheduling for certificates with custom validity
- Resolved sync conflict for simultaneously edited secrets across datacenters
- Fixed agent registration token validation for re-registered agents
Version 1.0.11¶
Release Date: 2026-01-10
Improvements¶
- PostgreSQL connection health monitoring with automatic reconnection
- Bidirectional sync architecture improvements for multi-region deployments
- Agent installation script fixes for air-gapped environments
- Onboarding flow improvements for remote deployment scenarios
Bug Fixes¶
- Fixed database migration rollback for failed upgrades
- Resolved LDAP group sync not reflecting membership changes
- Fixed certificate list pagination for projects with > 1000 certificates
Version 1.0.10¶
Release Date: 2026-01-03
Improvements¶
- Enhanced external change detection for CA-managed certificates
- Improved Helm chart values documentation with inline comments
- Certificate expiry notification batching to reduce alert fatigue
- Updated Go dependencies with security patches
Bug Fixes¶
- Fixed CRDT merge for concurrent secret version creation
- Resolved Azure Key Vault sync retry logic for transient failures
- Fixed OCSP responder returning incorrect status for renewed certificates
Version 1.0.9¶
Release Date: 2025-12-15
New Features¶
- Certificate Template System — Pre-configured certificate profiles for common use cases (Web Server, Client Auth, Code Signing, Email/S-MIME)
- Bulk Certificate Operations — Import and manage certificates in bulk via PEM bundles
- Enhanced Agent Discovery — Automatic discovery of certificates across agent-managed infrastructure
- Sync Improvements — CRDT-based multi-datacenter synchronization with improved conflict resolution
- Terraform Export — Export project configurations as Terraform HCL for infrastructure-as-code workflows
Improvements¶
- Improved certificate import validation and error reporting
- Enhanced OCSP responder performance with response caching
- Updated RBAC with granular certificate management permissions
- Improved audit logging with structured JSON output
- Enhanced health check endpoints with component-level status
Security Updates¶
- TLS 1.3 as default protocol
- Improved CSRF protection with double-submit cookie pattern
- Enhanced rate limiting with per-endpoint configuration
- Updated cryptographic dependencies
Version 1.0.8¶
Release Date: 2025-11-20
New Features¶
- External CA Integration — Connect to DigiCert, Venafi, Microsoft ADCS, and other external Certificate Authorities
- HSM Support — Hardware Security Module integration for key protection (PKCS#11, Azure Managed HSM)
- ACME Protocol — Automated Certificate Management Environment for automated certificate issuance
- Multi-Factor Authentication — TOTP-based MFA for enhanced account security
Improvements¶
- Redesigned certificate management interface
- Improved secret rotation scheduling
- Enhanced API rate limiting
- Expanded Azure Key Vault integration
Version 1.0.7¶
Release Date: 2025-09-10
New Features¶
- Zero-Knowledge Encryption — Client-side encryption for personal vault secrets
- SCEP Protocol Support — Simple Certificate Enrollment Protocol for device certificate management
- EST Protocol Support — Enrollment over Secure Transport for modern certificate enrollment
- Agent Proxy — Agents can proxy secret access for local applications
Improvements¶
- Improved database migration system
- Enhanced logging and monitoring
- Updated Kubernetes deployment manifests
- Performance improvements for large certificate stores
Version 1.0.6¶
Release Date: 2025-06-15
New Features¶
- Multi-Datacenter Sync — Bidirectional synchronization between MazeVault installations
- Azure Entra ID SSO — Single Sign-On with Azure Active Directory
- Project-Level RBAC — Granular role-based access control per project
- CRL Distribution — Automated Certificate Revocation List generation and distribution
Improvements¶
- Improved dashboard with real-time status updates
- Enhanced certificate search and filtering
- Updated API documentation with OpenAPI 3.0 specifications
- Improved container image security
Version 1.0.5¶
Release Date: 2025-03-20
New Features¶
- OCSP Responder — Real-time Online Certificate Status Protocol responder
- Secret Versioning — Full version history with rollback capabilities
- Agent Management — Centralized agent registration and monitoring
- LDAP Integration — Directory service authentication support
Version 1.0.4¶
Release Date: 2024-12-10
New Features¶
- Internal Certificate Authority — Full PKI with root and intermediate CA support
- Certificate Lifecycle Management — Request, approve, issue, renew, and revoke certificates
- Helm Charts — Standardized Kubernetes deployment via Helm
Version 1.0.3¶
Release Date: 2024-09-15
New Features¶
- Azure Key Vault Integration — Sync secrets with Azure Key Vault
- Secret Rotation — Automated and manual secret rotation
- Kubernetes Deployment — AKS deployment with Terraform
Version 1.0.2¶
Release Date: 2024-06-20
New Features¶
- Role-Based Access Control — User roles and permissions
- Project Management — Organize secrets into projects
- API v1 — Full REST API for secrets management
Version 1.0.1¶
Release Date: 2024-03-01
Initial Release¶
- Encrypted secrets storage with AES-256-GCM
- Web-based management interface
- PostgreSQL backend with Redis caching
- Docker Compose deployment
- Local authentication with SRP protocol
Support Policy
MazeVault supports the current version and one previous minor version. Customers on older versions are encouraged to upgrade to receive security updates and new features.