---
title: "hMailServer 6.3.4: a password could run code on Windows servers with JScript scripting"
url: https://www.hmailserver.co.uk/topic/28218/hmailserver-6.3.4-a-password-could-run-code-on-windows-servers-with-jscript-scripting
author: "chris"
published: 2026-09-27T02:47:34.540Z
updated: 2026-09-27T02:47:34.540Z
category: "Announcements & releases"
tags: ["release","security-advisory","security","schema","upgrade"]
site: hMailServer Community Forum
---

# hMailServer 6.3.4: a password could run code on Windows servers with JScript scripting

A password could run code inside the server (CVE-2026-100741, assigned through GitLab's CNA; the CVE record was not yet published when this was posted). On Windows, with event scripting switched on, the script language set to JScript and an `OnClientValidatePassword` handler in `EventHandlers.js`, any client that could reach a sign-in - SMTP AUTH, POP3, IMAP or anything else that checks an account's password - and name an existing, active account could have JScript of its own run inside `hMailServer.exe`, with the rights of the service's account, before it had authenticated. Before 6.2.25 that script could create any COM object, and from 6.2.25 it could with `ScriptAllowedObjects` at its shipped `*`, `WScript.Shell` among them, and so run any command the service's account may run. 6.3.4 fixes it. The flaw is in every release from 6.0.0 to 6.3.3: the escaping was checked at every one of those tags (GitLab issue 27). Treat any server older than 6.3.4 with event scripting on and JScript as its language as affected.

**Who is affected**

Only a Windows server whose administrator switched event scripting on. Scripting is off as shipped, the shipped language is VBScript, and no `EventHandlers.js` is installed.

- Through a password, a server whose script language is JScript and whose `EventHandlers.js` has an `OnClientValidatePassword` handler.
- The same flaw was open to a remote POP3 server through the UID it answers, on a JScript server with an `OnExternalAccountDownload` handler, and to a remote mail server through the error text it refuses a delivery with and the failed recipient's address, on a JScript server with an `OnDeliveryFailed` handler.
- A rule's Run function action wrote its function name into the call unescaped, in either language, so VBScript servers too. On a server with scripting on, whoever may edit a rule, a domain's own administrator included, could run code in the server's process.
- VBScript servers were not open through a password, a UID or an error text. The Linux builds before 6.3.4 had no script engine.

The server built each handler call as source text and escaped the apostrophe but not the backslash before it. Every JScript value is now escaped in one helper, and a rule's function name must be a plain identifier: ASCII letters, digits, `_` and `$`, not starting with a digit. On Windows any other name is refused as `HM5018` each time the rule fires; on Linux, whose JavaScript engine looks a handler up by name instead of building a call, such a name finds no function and nothing is run ([EventScripts.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/EventScripts.md)).

Until you can upgrade, switch event scripting off. A server that cannot do without its scripts should take the `OnClientValidatePassword`, `OnExternalAccountDownload` and `OnDeliveryFailed` handlers out of a JScript `EventHandlers.js` and reload the scripts, and, in either language, let nobody but the server administrator make or edit a rule with a Run function action.

**Before you upgrade**

- **Install 6.3.4 by hand, on every server.** The Windows installer is Authenticode-signed by Progressive Robot Ltd through Azure Artifact Signing, but the release carries no Sigstore bundle, so a server's live update, of any version, that is offered 6.3.4 says it cannot be verified and downloads nothing. On Windows run `hMailServer-6.3.4-x64.exe` over the existing installation; on Linux install the `.deb` with `apt` on Ubuntu 26.04 or 24.04, or the `.rpm` with `dnf` on Fedora 43 or 44 or Enterprise Linux 10. The `.deb` needs glibc 2.38 or later, so it does not install on Debian 12, and the `.rpm` does not install on Enterprise Linux 9.
- **A silent upgrade of a server with an administrator password needs it**, as before: `/adminpassword=<password>`, or, new in 6.3.4, the environment variable `HM_ADMIN_PASSWORD`, set in an elevated prompt, because it does not cross the UAC prompt. A password with a double quote goes in the variable: Inno Setup drops every double quote from its command line. The installer now hands the password to the database tools in that variable too. It used to put it on their command lines unquoted, so a password with a space, a double quote or backslashes before one failed the database step with exit code 3.
- **Back up the database and the data directory first.** The schema goes from 6040 to 6104 in 64 one-way steps. On MySQL and MariaDB, step 6102 converts every table to utf8mb4 and rebuilds each one, which takes time on a large database. It needs MySQL 5.7.9 or MariaDB 10.2.2 or later - on an older server the upgrade stops at step 6041 with error 1071 and changes nothing - and the ALTER privilege on the database. Two rows the new collation no longer tells apart stop it with error 1062 until one of them is removed; a step stopped part of the way is finished by running it again. Step 6101 adds two columns to `hm_messages`, which has a row for every stored message, and on a large store is not instant on every backend.
- **The database becomes the settings store.** At the first start the `[Settings]` section of `hMailServer.ini` is taken into the database. A line edited after the old server last started, including one edited to prepare the upgrade, is put back, so make such a change after upgrading. From then on a line edited in the file is ignored and put back (`HM5804`): change settings in the Control Panel, over COM or REST, or on Linux with `hmailserver --set-setting NAME=VALUE`.
- **A server from 6.2.28 to 6.3.3 still looks for updates at GitHub**, which has answered 404 since 18 September 2026. For as long as it stays on that version, add this under `[Settings]` in its `hMailServer.ini` and restart the service, and its update check works again:

  ```ini
  UpdateFeedUrl=https://updates.progressiverobot.com/releases.json
  ```

  Keep `UpdateAutoDownload` off on such a server until it has been upgraded by hand. Once 6.3.4 is installed the server reads https://updates.progressiverobot.com without being told (the stable channel at `/releases/latest`), and the line can then be cleared in the Control Panel or over REST, not in the file.
- **Linux packages for 6.3.4 are x86-64 only**: a `.deb` and an `.rpm`. The AArch64 packages and the AppImages were last published with [6.3.3](https://gitlab.com/hmailserver/hmailserver/-/releases/v6.3.3). Windows on ARM compiles but has never run, and there is no ARM64 installer.

**What changes on upgrade without a switch**

The 6.3.4 section of [CHANGELOG.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/CHANGELOG.md) lists 24 such changes. These are the ones most servers meet.

- SPF follows RFC 7208: mail from 127.0.0.0/8 and `::1` no longer passes unconditionally.
- The audit trail and the alerts are on, though nothing is mailed until `AlertRecipient` and `AlertSenderAddress` are set. Compromised-account detection runs in watch mode and holds nothing. A destination that answers 421 or a rate-limit code is paused, for 2 minutes at first and up to an hour (`OutboundBackoffMinutes`, `OutboundBackoffMaxMinutes`).
- MySQL and MariaDB connections use TLS whenever the database server offers it, without checking the certificate, and connect without it when it offers none. SQL Server sessions through MSOLEDBSQL 18 or SQL Native Client are encrypted whole, and tried once more without encryption when the failure reads as TLS unless `TlsMode` is `require` or `verify-full`; through SQLOLEDB, which the server uses where MSOLEDBSQL 18 or later is not installed and no failover partner is set, only the login is encrypted unless `[Database] TlsMode` is `require` or `verify-full`. `verify-full` checks the certificate. PostgreSQL is unchanged. The application log says at every start what the connection got ([DatabaseTls.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/DatabaseTls.md)).
- The administrator password is hashed again as PBKDF2 at the first administrator sign-in, and a browser session made under the old hash ends once. Where the service cannot write `hMailServer.ini` (the Linux packages, or a Windows service moved to `NT SERVICE\hMailServer`), the old value stays, `HM7494` is logged once, and you set the password again with `--set-admin-password`. The Windows installer now writes it as PBKDF2 itself.
- A password hash stored before 6.3.4 of a password with a character above U+00FF is refused, and the application log names the account: that hash was made of NUL bytes on Windows or question marks on Linux, and any other password of that form opened it. Set such a password again, and soon: until then a SCRAM-SHA-256 client that derives its key from those NUL bytes or question marks still opens the PBKDF2 hash, and on Linux the password with `?` in place of each such character still opens the account. ASCII and Latin-1 passwords sign in as before.
- A one-time code is taken once. A script that sent the administrator's password and a code with every REST request should sign in once (`POST /api/v1/session`) or use an API key; otherwise only its first request in each half minute is accepted.
- The outbound relay sends its OAuth2 token over TLS only. A route or the SMTP relay whose host is on `OutboundOAuth2Hosts` and whose connection security is none, or STARTTLS optional against a server that does not offer it, now sends nothing: the delivery fails with a temporary `450 4.7.0` and waits for its retries, and `HM5912` says to set the security to TLS or STARTTLS required.
- A domain can no longer be named as a directory the server keeps its own files in, such as `protected`, `quarantine` or `files`. One that already is can still be saved, and is named as `HM7597` at every start and on the setup checklist: rename it before you rely on a backup of it.
- A COM change to a route, relay, DNS black list, SURBL server, remote-domain policy, server message, blocked attachment, SSL certificate or group takes effect only at `Save()`. Scripts that relied on the old way must save.
- IMAP answers as the RFCs say where Dovecot's imaptest found it did not: some answers change from `BAD` to `NO`, and an `APPEND` stores the literal byte for byte.
- A restore refuses an archive with an absolute path, a `..` or a link in it, and the installer's 7-Zip is 26.03. Mail labelled ISO-8859-1 is decoded as windows-1252.
- Only a new installation is made secure before anyone configures it: a self-signed certificate, STARTTLS on 25, 587, 110 and 143, and TLS required for sign-in from the Internet IP range. The Windows installer does it; on Linux the service's first start under systemd within a day of `--create-database` does it, and with an AppImage or a container image, neither of which 6.3.4 ships, an administrator runs `--apply-new-install-defaults` by hand. A new Windows installation also runs the service as `NT SERVICE\hMailServer`, and a new installation gets a stored-secrets key, made by the Windows installer, and on Linux by the container's `--create-database` only; a new `.deb` or `.rpm` installation gets its key when an administrator runs `sudo hmailserver --create-stored-secrets-key`, which the setup checklist offers. An upgrade keeps its listeners, its service account and its secrets as they were: nothing is sealed until an administrator runs `--create-stored-secrets-key`, which the setup checklist offers.

**Fixed before release**

6.3.4 was audited area by area before it was cut, and its code was scanned by GitLab's SAST. The defects they found are fixed in this release. Several of these were in 6.3.3 as well.

- **Passwords outside Latin-1.** Every password hash was made over a conversion that turned the first character above U+00FF and everything after it into NUL bytes on Windows, and each such character into `?` on Linux, so a password of Cyrillic, Greek or CJK letters could be opened by any other password of its length and shape. Hashes are now made over UTF-8 (see the upgrade note above).
- **Sign-in.** SCRAM-SHA-256 accepted the account's own password for an account with a second factor, and a password past its maximum age (6.3.3 had both). A sign-in under a domain alias, or with a token, a certificate or a Kerberos ticket, escaped the country policy. One-time codes could be used again within their window, and at several places a wrong one was not counted.
- **Single sign-on and passkeys.** A single sign-on ticket could be redeemed in another person's browser. With a parent-domain relying party, a page on any sibling host could sign somebody in with their passkey (`passkey_allowed_origins` now names the origins). A switched-off domain still let its people in by passkey or single sign-on.
- **Delegated administration.** Where the server administrator's own mailbox is in a domain somebody else administers, that domain's administrator could become the server administrator through an app password on it, delete or rename it, or repoint its fetch account, over REST and COM. A credential confined to one domain could set another domain's webmail branding and declare spam traps in any domain.
- **Keys.** An app password or an administrator's support session could read the account's wrapped S/MIME, OpenPGP and zero-access keys. An app password could also replace the account's own S/MIME key and publish an OpenPGP key for the address, and a support session could change any of the account's keys or switch zero access off.
- **Collecting mail.** On a server that collects Microsoft 365 mail with its own OAuth2 token, any person could collect any mailbox the token reaches (a domain administrator over COM since 6.2.23 Alpha 1). A CR or LF in a fetch account's user name or password added commands, and a fetch account's host could be pointed inside the network through DNS after it was saved. Schema 6104 marks the fetch accounts made or changed from now on: one a person makes connects only to public addresses, unless the administrator allows private ones, and one made without the server's authority is never given the server's token. Accounts from before 6104, and an administrator's, are not marked, so review existing fetch accounts for hosts on `FetchOAuth2Hosts` after upgrading.
- **IMAP.** A heap-corruption abort when two sessions met on one message's keywords, flag changes lost when two arrived at once, an abandoned `APPEND` that left its file for good, an unbounded `LIST` pattern, and `ENVELOPE` and `BODYSTRUCTURE` values that broke the response. 6.3.3 had all of them.
- **The REST listener and the webmail.** Request headers were read from the body, which allowed a forged sign-in. One person could stall the webmail and the Control Deck for everybody. A Web Push endpoint could point inside the network. Large downloads were cut off and held whole in memory, and a request head that never ended could hold 16 MB.
- **GitLab's SAST (Semgrep).** Seven of its High findings were real, and are fixed: the crash-dump helper would load a `dbghelp.dll` put in `Bin`; the Control Panel's elevated service restart would run a `cmd.exe` left in its working directory; the installer handed the administrator password to `DBSetupQuick.exe`, and it to `DBUpdater.exe`, unquoted on their command lines; a malformed backup index was read past its end (two); and a test of the MIME parser compared pointers into two different arrays. 169 others were read and judged not exploitable, each with its reason in `.gitlab/security-exceptions.yml` (188 entries there, 19 of them re-reads of lines the fixes moved). Found beside them and fixed too: the MySQL client's DLLs were looked for in the current directory and along `PATH`, and a custom virus scanner whose command line holds a bare `%FILE%` was handed the path cut at its first space, scanned no file, and the message was delivered as clean.
- **The first security scans.** The installer's 7-Zip is 26.03 in place of 19.00, which predates the fixes for CVE-2023-31102 and CVE-2025-55188; a restore refuses an unsafe archive; MIME boundaries come from a generator seeded by the operating system; zlib is 1.3.2. The two static-analysis findings that were defects are fixed: on Linux the service account's name is read with `getpwuid_r`, and an inbound webhook's URL must be printable ASCII on both platforms.

**Also in this release**

Most of what is new is off until an administrator turns it on.

- **Mail flow**: remote-domain policies, per-destination throttling and IP warm-up, a send API for applications, DKIM key rotation, journaling, restricted delivery, message recall, and mail in to a webhook.
- **Anti-spam**: hardened greylisting, SMTP policy rules, allow and block lists with quarantine digests, mail flow rules with an outbound content policy, impersonation protection, attachment sandboxing, spam traps and country blocking.
- **Webmail and clients**: CalDAV and calendars with invitations, free-busy and delegation, rooms and equipment that answer bookings, contact groups and a directory, recover deleted items, expiring messages, offline mail, Web Push and OpenPGP in the browser.
- **Identity**: administrator roles, passkeys, OpenID Connect and SAML sign-in, SCIM provisioning, self-service password reset, sessions and devices, and breached-password checks.
- **Encryption**: zero-access mailboxes, mailbox encryption at rest, gateway encryption to partner domains, an organisation CA for S/MIME, Web Key Directory, and sealed stored secrets.
- **Compliance and administration**: eDiscovery with legal holds and verifiable exports, settings at server, domain and account level, profiles, `hmctl` and a PowerShell module, and a setup checklist.
- **Migration**: resumable migrations from IMAP, Google Workspace and Microsoft 365, and PST import with a reader of the project's own. No PST job runs until an administrator names `PstImportDirectory`, copies the file there and starts the job.
- **Operations**: storage compression and attachment de-duplication; object storage on an S3-compatible store or Azure Blob Storage, off until an administrator names a store (`MessageStoreBackend` is `file` as shipped); encrypted backups; event scripts on Linux in JavaScript (QuickJS); a read-only SNMPv3 agent, off, and answering nobody until a manager's address is in `SnmpAllowedAddresses`; and syslog.

The full list, with the operator document for each item, is the 6.3.4 section of [CHANGELOG.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/CHANGELOG.md).

**What 6.3.4 does not carry**

- No Sigstore bundle, so no server's live update installs it. From 6.3.5 the GitLab pipeline is to sign every file with Sigstore; none of its release jobs has run yet.
- No AArch64 `.deb` or `.rpm`, no AppImage, and no ARM64 Windows installer.
- No container image. The Dockerfile, the Compose file and the Helm chart are in the tree, nothing is published at `registry.gitlab.com/progressiverobot/hmailserver` yet, and the images published on `ghcr.io` before the suspension answer 404.
- No apt or dnf repository, and no winget or Chocolatey package of this project's in the public repositories (the `hmailserver` package on the Chocolatey feed is the upstream 5.6.8, unlisted).

**Downloads, and how to check them**

The release carries ten files:

- `hMailServer-6.3.4-x64.exe`, the Windows x64 installer; `hmailserver_6.3.4_amd64.deb` and `hmailserver-6.3.4-1.x86_64.rpm` for x86-64 Linux.
- An SBOM for each of those three, `<file>.cdx.json` (CycloneDX 1.6), whose subject is that file by its SHA-256 and SHA-512; and the source tree's SBOMs, `hmailserver.spdx.json` and `hmailserver.cyclonedx.json`.
- `hmailserver-6.3.4-SHA256SUMS.txt`, which names the other eight with their SHA-256, and `hmailserver-6.3.4-SHA256SUMS.txt.sig`, its signature, made with the SSH key that signs the release tags.

`https://updates.progressiverobot.com/download/hMailServer-x64.exe`, `/download/hmailserver_amd64.deb` and `/download/hmailserver.x86_64.rpm` always lead to that file of the newest stable release, never a pre-release's, and `https://updates.progressiverobot.com/download/` to that release's page.

To check a download, with OpenSSH 8.1 or later, in a clone of the repository (for `.gitlab/allowed_signers`) and with the downloads beside you:

```
ssh-keygen -Y verify -f .gitlab/allowed_signers -I christopher.j.holloway@outlook.com -n file -s hmailserver-6.3.4-SHA256SUMS.txt.sig < hmailserver-6.3.4-SHA256SUMS.txt
sha256sum -c hmailserver-6.3.4-SHA256SUMS.txt
```

The first must say `Good "file" signature for christopher.j.holloway@outlook.com`, and the second `OK` for every file (add `--ignore-missing` when you downloaded only some). On Windows, `Get-AuthenticodeSignature .\hMailServer-6.3.4-x64.exe` should also answer `Valid`, with a signer certificate for `CN=Progressive Robot Ltd`. The tag is signed with the same key: `git -c gpg.ssh.allowedSignersFile=.gitlab/allowed_signers verify-tag v6.3.4`. [SECURITY.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/SECURITY.md#verifying-a-release), "Verifying a release" and "Software bills of materials", has the rest, including how to check that an SBOM describes your file.

**Reporting a vulnerability**

Not in a thread here, and not in a public issue. Report it privately, as [SECURITY.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/SECURITY.md#reporting-a-vulnerability) says: a [confidential issue on GitLab](https://gitlab.com/hmailserver/hmailserver/-/issues/new?issue[confidential]=true) - check that it is still marked confidential before you submit it, and choose the **Security** template - or an email to contact-project+hmailserver-hmailserver-86730559-issue-@incoming.gitlab.com, which GitLab files as a confidential issue, so no GitLab account is needed.

[Release notes, checksums and downloads](https://gitlab.com/hmailserver/hmailserver/-/releases/v6.3.4) · [Newest stable release](https://updates.progressiverobot.com/download/)
