Skip to content

v26.9.0

Latest

Choose a tag to compare

@Innovarzweng Innovarzweng released this 01 Oct 00:23
878b1ab

BridgeLink 26.9.0 is a security-focused release: it completes the CVE-elimination work begun in 26.6.0, retires several unmaintained libraries, and modernizes the SQL Server and SFTP transports. It also carries every fix from the 26.6.1 security patch. Several of these changes are deliberately stricter than what they replace, so please read the compatibility notes below before upgrading.

⚠️ Upgrade & Compatibility Notes: Read Before Upgrading

Most installations upgrade cleanly with no action required. However, this release removes or hardens several long-standing behaviors, and a small number of configurations need attention before you start 26.9.0. Review the fourteen items below against your environment; each points to a detailed section later in these notes.

  1. Servers on the built-in Derby database need Java 21. Derby is upgraded to 10.17.1.0 to close CVE-2022-46337, and that Derby release requires Java 21. If conf/mirth.properties says database = derby (the default for a new install) and the server runs on Java 17, it stops at startup with embedded Derby requires Java 21+ as of 26.9; upgrade Java or switch to an external database. Servers on an external database (PostgreSQL, MySQL, SQL Server, Oracle) can stay on Java 17. See Java 21 and the Built-in Derby Database.

  2. jTDS driver retired: SQL Server channels must migrate; Sybase support is dropped. The bundled jTDS driver is removed. Any channel using a jTDS connection string (jdbc:jtds:sqlserver://host:port/db) must be updated to the Microsoft mssql-jdbc form (jdbc:sqlserver://host:port;databaseName=db, driver class com.microsoft.sqlserver.jdbc.SQLServerDriver) before upgrading, otherwise the channel fails to deploy with a ClassNotFoundException. There is no automated rewrite of channel connection strings. jTDS was also BridgeLink's only Sybase option, so Sybase connectivity does not survive this upgrade. Installs that run BridgeLink's own internal database on SQL Server must additionally update database.url (and any pinned database.driver) in mirth.properties before first startup. A Dynamic Lookup Gateway that uses its own SQL Server database (useExternalDb=true in conf/dynamic-lookup.properties) needs the same change to its database.url. See SQL Server Driver: mssql-jdbc Upgrade + jTDS Retirement.

  3. SQL Server certificates are now checked by default. The new SQL Server driver encrypts connections by default and checks the server's certificate. Coming from 26.6 or earlier, a SQL Server connection that did not set encrypt was either unencrypted or encrypted without a certificate check; after the upgrade it is encrypted and the certificate is checked. A SQL Server with a self-signed certificate, one from a CA Java does not trust, or one whose name does not match the URL's hostname will refuse the connection. That can stop the server from starting (if BridgeLink's own database is on SQL Server), fail Database Reader and Writer channels, and fail scripts that open their own connections. BridgeLink does not change any connection URL for you, so review them before upgrading. See SQL Server Driver: mssql-jdbc Upgrade + jTDS Retirement.

  4. XSLT steps that load outside files now fail. As part of the CISA ICSMA-26-253-01 fixes, an XSLT Transformer Step whose source document or stylesheet points to an external DTD or entity (a <!DOCTYPE ... SYSTEM "..."> line), or pulls in another file through xsl:import, xsl:include or document(), now fails the step with an ERROR instead of fetching it. Some older CDA and HL7 v3 feeds carry such a line. See Security Fixes: Inherited Mirth XXE and SQL Injection CVEs.

  5. Connectors on "Default" encoding may read and write text differently. TCP/MLLP and HTTP connectors whose Encoding is "Default" now honor the server-wide encoding property (ca.uhn.hl7v2.llp.charset, or the new server.defaultencoding), which they ignored in 26.6.x. Separately, a Windows server moving from Java 17 to Java 21 changes its default text encoding from windows-1252 to UTF-8. Nothing is migrated automatically. See Default Text Encoding Changes.

  6. SFTP algorithm hardening may reject very old servers. The upgraded jsch transport keeps its secure-by-default algorithm set, which excludes weak legacy families. Channels connecting to old or unpatched SFTP servers that offer only those families may fail negotiation. Connectivity to a specific legacy server can be restored through that channel's per-channel Configuration Settings without weakening any other channel. See SFTP Transport: jsch Upgrade.

  7. The legacy bundled web dashboard is removed. webadmin.war no longer ships and the /webadmin path now returns 404. Browser-based administration moves to the standalone BridgeLink WebAdmin console (see the end of these notes). If your team bookmarks or scripts against /webadmin, plan the switch before upgrading. Upgrading does not remove an existing webadmin.war: delete webapps/webadmin.war from the install directory after upgrading, or the old dashboard stays reachable at /webadmin.

  8. Password policy is now enforced at login. Stored passwords are checked against the configured password policy when users log in. Existing non-compliant passwords are not locked out: the user still logs in and is prompted to change the password. Administrators can optionally restrict such sessions to changing the password until it is rotated. See Password-Policy Enforcement at Login.

  9. Channel scripts that call the bundled OSHI library may break. The system-hardware library OSHI was upgraded across a major version (3.9.1 to 6.12.0), which also enables it on arm64/aarch64 hosts (AWS Graviton, Apple Silicon). No BridgeLink Java code uses OSHI, so the engine itself is unaffected, but channel JavaScript that reaches OSHI directly via Packages.oshi.* can fail after upgrading: several 3.9.1 method names were removed or moved in 6.x, and because Rhino resolves Java members at runtime, a broken call deploys cleanly and then fails per-message (in the quietest case, a JS Reader poll script that logs nothing). Audit channel scripts for Packages.oshi / importPackage of OSHI before upgrading. See arm64 / Graviton Support: OSHI + JNA Upgrade.

  10. Linux installers run the service as a dedicated user. The .sh and RPM installers now run blservice as the bridgelink system user (or an account you choose in the .sh installer) instead of root, and the service runs with NoNewPrivileges=true, so channel scripts can no longer use sudo or setuid programs. See Linux Installers Run the Service as a Dedicated User.

  11. The Windows service moves to a virtual account. The Windows installer now runs blservice as NT SERVICE\blservice, and an upgrade moves a service on Local System, Local Service or Network Service to it. That account reaches the network as the computer account, so a channel that reads a UNC share or uses SQL Server Windows authentication needs the computer account granted access, or a custom service account. See Windows Installer Runs the Service as a Virtual Account.

  12. A digest.iterations value above 10,000,000 locks every administrator out. BouncyCastle 1.86 caps PBKDF2 at 10,000,000 iterations. The default (600,000) is unaffected. If you raised digest.iterations above the cap, every login is rejected as a wrong password with nothing in the log. Raise the cap in the server's JVM options before upgrading, and do not lower digest.iterations. See Security: BouncyCastle 1.86.

  13. HL7 v2 messages with characters XML cannot hold now fail serialization. A message containing a character that XML 1.0 cannot represent, such as the ESC control character, now fails when it is converted to XML, instead of producing malformed XML that failed later or somewhere else. Expect such messages to error at the serialization step, and fix them at the source or strip the character before it reaches BridgeLink. See Bug Fixes.

  14. Your own AWS SDK v2 jars must match the upgraded SDK. The bundled AWS SDK for Java v2 moves from 2.15.28 to 2.55.8. If you added AWS SDK v2 service jars of your own (for example SQS, SNS or Secrets Manager clients) to custom-lib or to a plugin, replace them with version 2.55.8 before upgrading. Jars built for 2.15.28 fail against the new SDK. See AWS SDK for Java v2 Upgrade.

Java 21 and the Built-in Derby Database

Java 21 is recommended for every BridgeLink 26.9.0 server. Java 17 remains supported, with one exception: the built-in Derby database.

Your server's database On Java 17 On Java 21
Built-in Derby (database = derby) Stops at startup Runs
External database (PostgreSQL, MySQL, SQL Server, Oracle) Runs, unaffected Runs, recommended
  • What it checks: at startup, before it opens the database, the server checks whether database = derby and the Java version is lower than 21. If both are true, it logs this line at the ERROR level and exits, so nothing is changed on disk:
    embedded Derby requires Java 21+ as of 26.9; upgrade Java or switch to an external database
  • Why: the Derby fix for CVE-2022-46337 is only available in a Derby release that requires Java 21. Apache has not released a fixed Derby for Java 17.
  • What to do, pick one: install Java 21 and make sure BridgeLink uses it, or move BridgeLink to an external database and stay on Java 17.
  • The installers do not include Java. They use a Java 17 to 21 runtime already on the host, and accept Java 17 without warning, so on a Derby install a Java 17 host installs cleanly and then fails at first start. Install Java 21 before you install or upgrade. The RPM does not install Java. Install java-21-openjdk-headless first.
  • Your existing Derby database keeps its file format. The shipped database.url ends with upgrade=false, so 26.9.0 opens the database without rewriting it. Do not change it to upgrade=true: that rewrite into the 10.17 format is one-way.
  • Custom Java libraries: if you have added your own JAR files (custom code templates, a custom connector, a JDBC driver we do not ship, or anything in custom-lib), check that each one runs on Java 21 before you move a server to it. Watch logs/mirth.log on the first start for UnsupportedClassVersionError or NoClassDefFoundError.
  • Windows servers: moving from Java 17 to Java 21 changes the default text encoding. See Default Text Encoding Changes.
  • How to confirm: every start writes one line to logs/mirth.log naming the Java version, the database type and the default character set, for example Running OpenJDK 64-Bit Server VM 21.0.12 on ... derby, with charset UTF-8.

🛡️ Security: CVE Dependency Upgrades

This release completes the CVE-elimination work carried over from 26.6.0. The XStream, BouncyCastle, and Rhino upgrades that 26.6.0 evaluated and intentionally deferred now land with their regression coverage in place, joined by the mssql-jdbc, jsch, Jersey/HK2, Jackson and Derby upgrades.

Library Before After
XStream 1.4.20 1.4.21
BouncyCastle (bcprov / bcpkix / bcutil jdk18on) 1.78.1 1.86
Rhino (JavaScript engine) 1.7.13 1.7.15.1
Apache Derby (derby, derbyshared, derbytools) 10.16.1.1 10.17.1.0 (already in 26.6.1)
mssql-jdbc 8.4.1.jre8 12.10.2.jre11
jsch (com.github.mwiede) 0.2.18 2.28.5
Jersey (client / common / server / container / media) 2.22.1 2.48
HK2 2.4.0-b31 2.6.1
Jackson (12-jar family, incl. jackson-databind) 2.14.3 2.18.10
PostgreSQL JDBC 42.7.11 42.7.12

CVEs addressed by these upgrades:

Also bumped for CVE hygiene alongside the above: netty 4.1.135.Final to 4.1.137.Final, and swagger-core 2.0.10 to 2.2.28 as the companion to the Jackson bump.

Notes:

  • The XStream and BouncyCastle upgrades ship behind added serialization round-trip and cryptographic regression coverage, together with the MirthDomReader post-migration reload fix.
  • The Rhino bump ships with ES6 seam-characterization and E4X round-trip regression tests; channel JavaScript behavior was verified unchanged on the new engine.
  • The Jersey/HK2 upgrade stays on the javax-package line (packages remain javax.ws.rs.* / javax.inject.*); it is a security refresh, not a Jakarta re-platforming. Its companion jars move with it: javassist 3.26.0-GA to 3.30.2-GA, mimepull 1.9.7 to 1.9.15, osgi-resource-locator 1.0.1 to 1.0.3, and new jersey-hk2 and aopalliance-repackaged jars. javax.ws.rs-api and javax.inject are replaced by jakarta.ws.rs-api 2.1.6 and jakarta.inject 2.6.1, which despite the jar names still provide the javax.* packages.
  • jetty (12.0.33), log4j (2.25.4), pdfbox/fontbox/xmpbox (2.0.36), and the commons-* family are unchanged from 26.6.0.

Security Fixes: Inherited Mirth XXE and SQL Injection CVEs

These three fixes answer CISA advisory ICSMA-26-253-01. Two are XML external entity (XXE) flaws, where a crafted XML document makes the server read a file or call a web address it should not. The third is a SQL injection flaw, where crafted input gets run as a database command. They are the same fixes that shipped in 26.6.1.

  • CVE-2026-78224: the XSLT Transformer Step no longer loads outside DTDs or stylesheets.
    • A source document or XSLT template that points to an external DTD or external entity (a <!DOCTYPE ... SYSTEM "..."> line) now fails the step, with the error logged at the ERROR level. Some older CDA and HL7 v3 feeds carry such a line. Expect those messages to error, and look into them.
    • A stylesheet that pulls in another file or web address, through xsl:import, xsl:include or document(), also fails the step now. If a stylesheet loads a lookup table that way, supply that data another way.
    • Self-contained transforms with no outside references are unaffected, and Java extension functions in stylesheets keep working.
    • If the step uses a custom TransformerFactory (for example Saxon) that does not accept these protections, the step still runs, but it is not protected, and the server logs a WARN line starting with XSLT Step: custom TransformerFactory ... rejected. Watch for that line after upgrading.
  • CVE-2026-82578: XML batch processing with the XPath split option no longer loads outside entities or DTDs. Batch XML is now read with a locked-down parser before the XPath split runs. A batch that used to pull in an external entity or DTD is split without it. A batch with only an internal DTD still parses and splits normally, and XPath queries that rely on namespaces match the same nodes as before.
  • CVE-2026-82583: the Database connector's Get Tables call is closed to SQL injection. This is the POST /connectors/jdbc/_getTables API, used when you browse tables while setting up a Database Reader or Writer.
    • The selectLimit query is run only when it matches one of the shipped safe shapes (SELECT * FROM ? with an optional LIMIT, TOP, WHERE ROWNUM or FETCH FIRST clause). It now runs with a five second timeout and returns at most one row.
    • A custom selectLimit that does not match, or a table or schema name that contains anything other than letters, digits, _, . or $, is not run. BridgeLink reads the columns through the standard database lookup instead. That lookup gives the same column list but can be slower on very large databases.
    • Get Tables calls now appear in the audit log. The connection URL and the password are left out of the record.

Security: BouncyCastle 1.86

BouncyCastle moves from 1.78.1 to 1.86 in the server, Administrator client and CLI libraries (bcprov, bcpkix and bcutil jdk18on). Deployments on default settings need no action.

  • CVE-2026-8763 (critical): an X.509 name-constraints bypass (a trailing dot on a DNS name) in certificate-path validation done through BouncyCastle.
  • CVE-2026-13506 (high): denial of service from deeply nested ASN.1 structures under lazy parsing.
  • PBKDF2 iteration cap (CVE-2026-17508). 1.86 rejects a PBKDF2 derivation above 10,000,000 iterations (org.bouncycastle.pbe.max_iteration_count, default 10,000,000). BridgeLink hashes administrator passwords with PBKDF2 at digest.iterations (default 600,000, unaffected).
    • If you set digest.iterations above 10,000,000, every administrator login fails after the upgrade. The failure is silent: each login is rejected as an incorrect username or password, nothing is written to the server log, and each attempt still counts toward account lockout. If every administrator is suddenly locked out after this upgrade, check digest.iterations before starting a credential reset.
    • Before upgrading, add -Dorg.bouncycastle.pbe.max_iteration_count=<value>, at least your digest.iterations value, to the server's JVM options file.
    • Do not lower digest.iterations as a fix. Stored password hashes do not record their iteration count, so lowering it makes every existing password fail to verify.
    • Raising the cap also widens the limit CVE-2026-17508 puts on untrusted PBKDF2 input, so keep it no higher than you need.
  • Stricter ASN.1 time decoding. BouncyCastle now rejects malformed ASN.1 UTCTime and GeneralizedTime values. This reaches channel scripts and plugins that parse or verify signatures, certificates or CRLs with BouncyCastle. A UTCTime without the trailing Z can be accepted again with -Dorg.bouncycastle.asn1.allow_zoneless_utctime=true; BridgeLink does not set it.
  • BouncyCastle's own PKCS12 keystore (only when a script or plugin explicitly asks for KeyStore.getInstance("PKCS12", "BC")) now writes 600,000 PBE iterations instead of 51,200, so storing and loading one costs about twelve times more. org.bouncycastle.pkcs12.store_it_count sets the count. BridgeLink's own keystore is served by the JDK, not BouncyCastle, and is unaffected.
  • Removed legacy APIs. 1.86 removes the deprecated org.bouncycastle.pqc.crypto ML-DSA, ML-KEM and SLH-DSA classes and the legacy Rainbow, Picnic, FrodoKEM and CMCE implementations. A channel script using the ML-DSA, ML-KEM or SLH-DSA classes must move to the standardized classes under org.bouncycastle.crypto; Rainbow and Picnic have no replacement. BridgeLink itself uses none of them.

🧹 Security: Unmaintained Library Removals & Replacements

Beyond version bumps, this release removes or replaces several bundled libraries that are no longer maintained upstream, eliminating a class of long-term CVE exposure rather than patching around it. The most visible swap is the PDF/RTF engine, and Document Writer retains full PDF and RTF output after it, with no feature regression.

Removed Replaced with Reason
iText 2.1.7 / itext-rtf 2.1.7 OpenPDF 2.0.5 / OpenRTF 1.2.1 Unmaintained PDF/RTF engine
commons-httpclient 3.0.1 HttpComponents 4.5.13 (already shipped; 3.x call sites repointed, jar removed) End-of-life, unpatched CVE-2020-13956
webdavclient4j-core 0.92 Sardine 5.9 Pulled in vulnerable httpclient
jai_imageio jai-imageio-core 1.4.0 / jai-imageio-jpeg2000 1.4.0 Unmaintained imaging codec
saaj-impl 1.0 saaj-impl 1.5.3 Security refresh
wsdl4j 1.6.2-fixed wsdl4j 1.6.3 Security refresh
backport-util-concurrent java.util.Collections (JDK-native) Dead code removed

Scanner note: OWASP Dependency-Check may report CVE-2021-37533 (Apache Commons Net, fixed in 3.9.0) against commons-httpclient, commons-el 1.0 and not-going-to-be-commons-ssl 0.3.18. That is a naming collision in the scanner, not an exposure: BridgeLink has shipped the fixed commons-net 3.9.0 since 26.6.0 and does not use those jars for FTP.

🔐 SQL Server Driver: mssql-jdbc Upgrade + jTDS Retirement

The JDBC connector's Microsoft SQL Server driver moves to a current, actively maintained release (8.4.1.jre8 to 12.10.2.jre11), and the long-obsolete jTDS driver is retired entirely. This is the change most likely to require action before you upgrade, so review the points below if any channel or your internal database talks to SQL Server.

  • jTDS is removed. jtds-1.3.1.jar and its vendored TLS source patch are gone from every shipped location, and the "SQL Server/Sybase (jTDS)" entry is removed from the driver dropdown (DriverInfo) and from dbdrivers.xml. Sybase support is dropped with it: jTDS was BridgeLink's only Sybase JDBC option, and mssql-jdbc does not speak the Sybase/TDS dialect.

  • Channel URL migration required. Any channel using the jTDS driver (net.sourceforge.jtds.jdbc.Driver, jdbc:jtds:sqlserver://host:port/db) must be migrated to mssql-jdbc (com.microsoft.sqlserver.jdbc.SQLServerDriver, jdbc:sqlserver://host:port;databaseName=db) before upgrading, or the channel will fail to deploy with a ClassNotFoundException. There is no automated rewrite of channel-stored connection strings.

  • Action required: SQL Server certificates are now checked by default. The driver upgrade fixes CVE-2025-59250. From driver version 10.2 onward Microsoft changed the encrypt default from false to true, and the driver checks the server's certificate whenever the connection is encrypted. Coming from 26.6 or earlier, connections that did not set encrypt were either unencrypted or encrypted without a certificate check; after the upgrade they are encrypted and the certificate is checked. If your SQL Server uses a self-signed certificate, a certificate from a CA the Java runtime does not trust, or one whose name does not match the hostname in the URL, those connections fail with "could not establish a secure connection", "PKIX path building failed" or "Failed to validate the server name". Four places can be affected:

    • BridgeLink's own database (database.url in mirth.properties): the server will not start.
    • Database Reader and Database Writer connectors: the server starts, but those channels error.
    • Scripts that open their own SQL Server connections.
    • The Dynamic Lookup Gateway's own database (database.url in conf/dynamic-lookup.properties, when useExternalDb=true): the server starts, but the gateway does not initialize.

    BridgeLink does not change any connection URL during the upgrade, so review them before you upgrade. The best fix is a SQL Server certificate BridgeLink can validate: one issued by a public CA, or by your internal CA with its root added to the Java trust store. If that is not possible, add ;trustServerCertificate=true to the affected URL, which keeps encryption on but skips the certificate check. Adding ;encrypt=false is not enough on its own: if your SQL Server forces encryption, the connection is still encrypted and the certificate is still checked. URLs that already set encrypt=true are not affected.

  • Internal mcserver database (SQL-Server-backed installs only). Installs running BridgeLink's own backing store on SQL Server (database = sqlserver) must manually update database.url (and any pinned database.driver) in mirth.properties to the mssql-jdbc form before starting 26.9. A first-startup migrator strips the retired jTDS entry from the persisted driver list, or replaces it with the Microsoft SQL Server entry when jTDS was the only SQL Server driver listed, so the dropdown never loses SQL Server. That cleanup does not rewrite mirth.properties.

  • Dynamic Lookup Gateway with its own SQL Server database. If conf/dynamic-lookup.properties has useExternalDb=true and database = sqlserver, the gateway used the jTDS driver by default in 26.6 and earlier, and the shipped example URL was the jTDS form. It now defaults to the Microsoft driver, but nothing rewrites the URL, and upgrades keep your existing file. Before upgrading, change database.url from jdbc:jtds:sqlserver://host:port/db to jdbc:sqlserver://host:port;databaseName=db, and remove any database.driver = net.sourceforge.jtds.jdbc.Driver line. If you do not, the server still starts, but the gateway fails to initialize (mirth.log shows Error instantiating plugin), and channels that call lookup functions fail. The certificate note above applies to this connection as well. Gateways on BridgeLink's internal database (useExternalDb=false, the default) are covered by the mirth.properties item.

  • Full runbook: docs/mssql-jdbc-encryption-compatibility.md in the repository.

🔐 SFTP Transport: jsch Upgrade

The File connector's SFTP transport now runs on a current release of com.github.mwiede:jsch (0.2.18 to 2.28.5), closing out staleness and CVE-hygiene exposure and maximizing distance from future advisories. For channels connecting to modern SFTP servers this is a drop-in upgrade, with no API changes and no reconfiguration required.

  • jsch's secure-by-default hardened algorithm set is unchanged by the bump: it still excludes the weak legacy families (diffie-hellman-group14-sha1 kex, plain ssh-rsa signatures, 3des-cbc/aes128-cbc ciphers, hmac-md5 and hmac-sha1-96 MACs). The 2.28.5 upgrade only adds algorithms (post-quantum kex, OpenSSH certificate host keys) and reorders cipher preference (AES-GCM now preferred over AES-CTR).
  • Legacy-server impact: channels connecting to old or unpatched servers that offer only those excluded families may fail negotiation with JSchAlgoNegoFailException: Algorithm negotiation fail. This is the connector's long-standing secure-by-default behavior, not a new regression.
  • Workaround: each affected channel's per-channel SFTP Configuration Settings (piped straight to session.setConfig()) can restore connectivity to a specific legacy server without weakening defaults for any other channel.
  • Full runbook: docs/sftp-legacy-algorithm-compatibility.md in the repository.

Default Text Encoding Changes

Starting with Java 18, the JVM's default text encoding is UTF-8 on every operating system. Any connector whose Encoding is left at "Default" follows that default: on a pre-Java-18 Windows server it resolved to windows-1252, and on Java 18 and later it resolves to UTF-8. Linux and macOS servers almost always used UTF-8 already.

  • Affected connectors: TCP/MLLP, File (text mode), Database (byte columns) and SMTP, the connectors whose Encoding field is commonly left at "Default". HTTP connectors ship an explicit UTF-8 default, so they are affected only where an administrator changed that field to "Default" (or to "NONE" on a Sender whose remote response omits a charset).
  • Changed on any Java version: TCP/MLLP and HTTP connectors on "Default" now honor the server-wide encoding property, which the File, Database and SMTP connectors always did. If ca.uhn.hl7v2.llp.charset is already set in your mirth.properties, check its value before upgrading: those connectors ignored it before and will follow it now.
  • New server.defaultencoding property: the documented name for that same server-wide value. It takes precedence over the legacy alias ca.uhn.hl7v2.llp.charset when both are set. An invalid value is logged at ERROR and ignored.
  • How to tell whether this affects you: at every startup the server compares the JVM default charset with the host's native encoding and writes a WARN to mirth.log when they differ: JVM default charset is ... but the host (native) encoding is .... mirth.log rolls at 500KB, so check it soon after the restart. The absence of the warning does not clear you for the TCP/MLLP and HTTP change above.
  • Remedy: to keep the old Windows encoding for "Default" connectors, set server.defaultencoding = windows-1252 in conf/mirth.properties, or pin the Encoding field on each affected connector.
  • Not covered by the setting: channel scripts calling FileUtil.read or FileUtil.write without an explicit charset, and the Document Writer's RTF output, follow the JVM default directly. FileUtil.read and FileUtil.write take no charset, so in those scripts read the bytes and decode them yourself, for example new java.lang.String(FileUtil.readBytes(fileName), 'windows-1252').
  • Nothing is changed automatically. The upgrade does not write server.defaultencoding for you.
  • The mirth.log file appender now always writes UTF-8, regardless of the JVM default.

🖥️ arm64 / Graviton Support: OSHI + JNA Upgrade

BridgeLink runs on the JVM and was already arm64-capable, but the bundled OSHI system-hardware library (with its JNA native bindings) was too old to work on arm64/aarch64 hosts: channel scripts that read CPU or memory stats via Packages.oshi.* failed on AWS Graviton and Apple Silicon with LinuxCentralProcessor: Couldn't find physical package count. This release upgrades OSHI across a major version, with the mandatory JNA lockstep bump, resolving that error on aarch64.

Library Before After
OSHI (oshi-core) 3.9.1 6.12.0
JNA (jna / jna-platform) 4.5.2 5.18.1
  • No engine impact. No BridgeLink Java source imports OSHI or JNA (verified across all modules); the only consumers are Rhino channel scripts. The JNA bump also aligns the two jars that reference JNA (jsch's ssh-agent path and pgjdbc's Windows SSPI path) with the 5.x line they expect.
  • Channel-script compatibility is the real risk surface. OSHI 6.x is a major-version API change. Because Rhino resolves Java members only at runtime, a script calling a removed/moved method deploys cleanly and then fails per-message, and filter/transformer errors write nothing to mirth.log unless log.errorevent.enabled=true. Audit channel scripts for OSHI use before upgrading.
  • Known breaks on the common monitoring surface: the no-arg processor.getSystemCpuLoad() is removed (use the tick-delta form getSystemCpuLoadBetweenTicks(priorTicks), caching the prior tick array); getVendorFreq() moved to getProcessorIdentifier(); memory.getSwapUsed() / getSwapTotal() moved under memory.getVirtualMemory().
  • Do not "fix" it with getSystemCpuLoad(long). In 6.x that overload blocks the calling thread for the supplied millisecond interval before returning; dropped into a per-message channel it serializes throughput. CPU frequency may also legitimately read 0 / N/A on Graviton.
  • Full mapping of each old call to its 6.x replacement: docs/irt-1801-oshi-6x-enlighten-migration.md in the repository.

AWS SDK for Java v2 Upgrade

The AWS SDK for Java v2, used by the File connector's S3 mode, moves to a current release. The old SDK does not work with the Jackson version in this release: without this upgrade, an S3 File Reader or File Writer using the default credential provider chain (for example an EC2 instance role) would fail.

Library Before After
AWS SDK for Java v2 2.15.28 2.55.8
  • S3 connectors work as before with the default credential chain, static access keys and temporary credentials.
  • Advanced S3 Settings region list: the Administrator's region dropdown now lists the newer AWS regions (53, up from 31).
  • Your own AWS SDK v2 jars: if you added AWS SDK v2 service jars (for example SQS, SNS or Secrets Manager clients) to custom-lib or to a plugin, replace them with version 2.55.8. Service jars built for 2.15.28 fail against the upgraded SDK.
  • Upgrading by hand rather than with an installer: replace the whole server-lib directory so no 2.15.28 jars remain.

🌐 WebAdmin Landing & Migration

The legacy bundled web dashboard (webadmin.war) is retired in favor of the standalone BridgeLink WebAdmin console (see the section at the end of these notes), and the server now signposts users to it rather than serving a stale in-process UI.

  • New unauthenticated GET /webadmin-url endpoint returns {"url":"<webadmin.url>"} (JSON), driven by the new webadmin.url property.
  • The old /webadmin path now returns 404; / serves a lightweight signpost page. The distribution no longer ships webadmin.war.
  • Remove it yourself when upgrading. The upgrade does not delete a webadmin.war left by an earlier version, and the server still loads any .war file in webapps/. After upgrading, stop the server, delete webapps/webadmin.war from the install directory, and start the server again. Until you do, the legacy dashboard is still served at /webadmin.
  • The Swing Administrator shows a WebAdmin migration dialog at every login until the user ticks "Don't show this warning again".

🧩 New Feature: WebAdmin Core API

Core gains a substantial REST surface that powers the browser-based WebAdmin console: the channel editor, script tooling, and datatype configuration in WebAdmin all build on it.

  • Script validation: POST /server/_validateScript and POST /server/_validateScripts compile-check one or many Rhino scripts server-side and return structured results (the batch form is keyed by caller-supplied ids), so the editor can flag JavaScript errors without deploying a channel.
  • Data type parse / serialize and connector default properties for the channel editor.
  • Cron / next-fire-time validation, template preview, script references, and server-side JavaScript pretty-print.
  • Datatype defaults for extensions: GET /extensions/{extensionName}/webadmin/datatype-defaults/{dataTypeName} returns the XML serialization of an extension's default DataTypeProperties, the datatype counterpart to the existing connector defaults endpoint. Read-only; manifest/defaults reads remain canonical-path guarded against the extensions directory. A sample extension (mock DIMSE) demonstrating the contract is included.

(Contributed: PR #182.)

🔑 New Feature: Password-Policy Enforcement at Login

Stored passwords are now checked against the configured password policy at login, so a tightened policy actually reaches existing accounts instead of applying only to new passwords. Existing non-compliant passwords are not locked out: the user still logs in and is prompted to change the password, so the policy can be adopted without disrupting existing users.

  • password.enforceatlogin (default true) turns the check on.
  • password.restrictgracesessions (default false), when enabled, confines a session that logged in with a non-compliant password to changing its own password (other calls return HTTP 403) until the password is rotated.
  • Works with two-step MFA logins: the password-policy verdict is carried to the step that completes the login.

(Contributed: PR #194.)

New Feature: SMTP Sender CC and BCC

The SMTP Sender now supports CC and BCC recipients, in the connector settings, in the test-email dialog, and in the SMTPConnection.send JavaScript API (a new overload with cc and bcc arguments). The "Send an Email" code template is updated to match. Existing channels saved without CC/BCC keep working unchanged.

(Contributed: public PR #177.)

Stuck Channels: Stop Grace Period, Thread Diagnostics and Bounded Halt

A channel whose connector waits on something that never answers (a partner system that accepts a connection and goes silent, or a database call that never returns) can no longer hold up the rest of the server. Before this release Stop never returned for such a channel, Halt could hang on the same work, and because undeploy stops a channel first, one stuck channel could block Redeploy All and server shutdown for every other channel.

  • Stop has a grace period. A stop waits at most server.channelstopgraceperiod seconds (Settings > Server > "Channel Stop Grace Period", default 120) for its threads and connector stop hooks. When the period runs out the stop fails with an error naming the stuck thread and its top stack frames, and the channel stays Stopping; nothing escalates to halt on its own. If the stuck work later finishes, the stop completes and the channel reaches Stopped by itself. Keep the period at 10 seconds or more, since a source queue polls in one-second slices. Setting it to 0 restores the old wait-forever stop and turns off the overdue flag below.
  • Only stop is bounded. Deploy, start, pause, resume and remove-all-messages wait as before.
  • Undeploy and Redeploy All no longer wait forever on one channel. If a channel does not stop in time, its undeploy stops there, the channel is left Stopping, and the rest of an Undeploy All or Redeploy All carries on. Undeploying a channel that is already Stopping is refused with advice to halt first, because tearing it down under a live dispatch thread could deliver a message twice.
  • New endpoint GET /channels/{channelId}/_threads lists every live thread belonging to the channel with its state, the lock it waits on and its top stack frames, plus what the last stop timed out on. It returns stack frames only, never message content or connector settings, and requires the dashboard view permission. WebAdmin shows it as Thread Diagnostics on the dashboard. Dashboard status also gains stateSince and lifecycleOverdue, set when a channel has been Stopping or Starting longer than the grace period.
  • Halt now always finishes. It still interrupts everything at once, then gives those threads a fixed two seconds (independent of the grace period) and marks the channel Stopped. Anything still running is logged with its stack frames and recorded as abandoned. An abandoned thread cannot later update connector state, release a permit, or resume as a second queue sender in the restarted channel. The REST halt call returns within about 34 seconds.
  • Unchanged: halt still trades a possible duplicate delivery for never losing a message. A message part-way through delivery may be sent again once the channel restarts, and because a start no longer waits for abandoned threads, restarting soon after a halt makes that duplicate reachable sooner. The WebAdmin halt confirmation now says so.

Linux Installers Run the Service as a Dedicated User

BridgeLink refuses to run as root, but earlier Linux installers (.sh and RPM) registered the blservice systemd unit with no user, so a default install started as root and exited at first boot. Both Linux installers now run the service as a system user: bridgelink for the RPM, and bridgelink or an account you choose in the .sh installer.

  • The installer creates the user if needed, gives it ownership of the installation directory, and sets it in a systemd drop-in, /etc/systemd/system/blservice.service.d/10-bridgelink-user.conf.
  • For an unattended .sh install, set -Vunix_service_user=<account>. Running as root is still possible with "-Vunix_service_account_type=root (not recommended)" (keep the quotes); the service then starts only with server.allowRoot = true in conf/mirth.properties.
  • On upgrade, the account the service already runs as is kept, including one you set with systemctl edit blservice. Uninstalling removes the drop-in and leaves the user.
  • The drop-in sets NoNewPrivileges=true, so channel scripts can no longer gain privileges through sudo or setuid programs. If a channel needs that, do not edit the installer's drop-in (it is rewritten on every upgrade): run systemctl edit blservice, add NoNewPrivileges=false under [Service], and restart. An install that already runs under a User= drop-in of your own does not get the installer's drop-in or this setting.

Windows Installer Runs the Service as a Virtual Account

BridgeLink refuses to run as an administrator, and Local System is one. Earlier Windows installers defaulted to Local System, so a default install ended with a service that never started (mirth.log shows BridgeLink is running as root/Administrator and nothing listens on 8443). The installer now runs blservice as NT SERVICE\blservice, the service's own virtual account: Windows manages it, it has no password, and it is not an administrator. The installer gives it write access to the installation directory.

  • Custom account is still offered, for SQL Server Windows authentication, UNC shares or other domain resources.
  • Local System (not recommended) is still offered; the service then starts only with server.allowRoot = true in conf/mirth.properties.
  • On upgrade: a custom account is kept (leave the password blank to keep the stored one), including for unattended -q upgrades, which previously reset the service to Local System and discarded the password. A service on Local System, Local Service or Network Service moves to the virtual account, unless server.allowRoot = true is set in conf/mirth.properties (a -Dserver.allowRoot=true line in blservice.vmoptions alone does not count).
  • Unattended installs: the default needs no response-file line. For a custom account set service_account_type=Custom account..., service_account_user and service_account_password, writing a backslash in the user name twice (service_account_user=.\\svc-bl). An old service_account_type=Local System line now gives the virtual account; to choose Local System on purpose, use service_account_type=Local System (not recommended).
  • The virtual account reaches the network as the computer account. If a channel reads a UNC share or connects to SQL Server with Windows authentication, grant the computer account access, or install with a custom account.

Unattended Windows Installs Install WebAdmin

An unattended Windows install (-q) used to skip WebAdmin silently while its response file still recorded installWebAdmin=true. It now runs the WebAdmin installer and waits for it, so the run ends with the BridgeLinkWebAdmin service listening on 8444. To skip WebAdmin, pass -VinstallWebAdmin=false or set installWebAdmin=false in the response file. If the WebAdmin installer fails or takes longer than 15 minutes, the installer log says WebAdmin was not installed: with the reason; WebAdmin's own log is webadmin-setup.log in the installation directory.

RPM Upgrades Keep Your conf/ Files

Upgrading with rpm -U no longer overwrites your configuration. Earlier RPMs replaced every file in conf/ with the packaged template, losing your edits and the keystore password generated on first start, so after the upgrade the server reported "started" but did not listen on HTTPS (8443). This also protects an upgrade from 26.6.x.

  • mirth.properties, dynamic-lookup.properties, log4j2.properties, log4j2-cli.properties, mirth-cli-config.properties, dbdrivers.xml and the launcher JVM option files (blservice.vmoptions, blserver.vmoptions, blcommand.vmoptions) are now kept across upgrades, so a changed heap size (-Xmx) survives.
  • A file you changed is kept. If the new template differs, it is written next to it as <name>.rpmnew. The new mirth.properties keys are already added to your file for you. If you edited blcommand.vmoptions, merge in the new --add-opens lines from blcommand.vmoptions.rpmnew. A file you never changed is replaced with the new template.
  • To repair or reinstall, upgrade in place with rpm -U --replacepkgs. Do not remove the package first. rpm -e keeps a changed file as <name>.rpmsave but leaves the keystore and database in appdata/ in place, so a following rpm -i starts on a fresh mirth.properties whose keystore passwords do not match the old keystore, and HTTPS never comes up. Any other edits to that file, such as the database connection, are also only in the .rpmsave.
  • If you already removed and reinstalled, copy conf/mirth.properties.rpmsave back over conf/mirth.properties and run systemctl restart blservice.
  • Do not delete appdata/keystore.jks to clear the error. It also holds the server's encryption key, and encrypted data cannot be read without it.

The .sh installer already kept conf/ and is unchanged.

Upgrading from 26.6.0 or 26.6.1

  • Servers on 26.6.1 upgrade to 26.9.0 in place with no manual database steps. 26.6.1 is schema-identical to 26.6.0.
  • Unrecognized database versions now stop startup. If the database's schema version is one this release does not recognize, startup aborts with a clear MigrationException naming the version, instead of silently re-running the old migration steps against it. A fresh install is unaffected.
  • Built-in Derby servers: confirm Java 21 is in place first (see Java 21 and the Built-in Derby Database). The upgrade will not stop you, but the server will not start afterward on Java 17.

🐛 Bug Fixes

  • Channel tags deleted on save (Administrator): on JavaFX runtimes updated after July 2026, the channel tag field failed to load and saving a channel removed all of its tags. The tag field works again, and saving no longer removes tags when it cannot load. Also fixes double-click channel editing becoming disabled for the rest of a session.
  • Overlapping "Reprocess and overwrite" jobs on source-queued channels: two overlapping jobs could fail with duplicate-key errors and leave the affected messages erroring on every poll, including across restarts. (Contributed: PR #191.)
  • WebAdmin channel list failed to load: a channel script containing a control character (for example an MLLP framing byte) no longer makes the channel list fail to load for every user.
  • Server restart after an aborted startup: when startup is aborted (database unreachable, port in use, resource init failure), the process now exits with status 1, so service managers configured to restart on failure do so.
  • Dynamic Lookup Gateway keys with special characters: lookup keys and group names containing slashes, percent signs or backslashes can be fetched, edited and removed again; the Administrator now sends them in the request body. Keys literally named get, set or delete must use the new body-based endpoints.
  • Dynamic Lookup JSON import: importing a JSON-typed lookup group now correctly dispatches to the JSON import path (previously routed to the non-JSON importer).
  • Web Service Listener on Java 19 and later: every inbound SOAP request failed with Unable to create SAAJ meta-factory, because the listener's worker threads could not see the SAAJ implementation on newer Java versions. Web Service Listener channels now work on Java 21.
  • Dynamic Lookup Gateway on SQL Server: the gateway's sqlserver database type defaulted to the jTDS driver, which no longer ships. It now defaults to the Microsoft driver (com.microsoft.sqlserver.jdbc.SQLServerDriver). The comments in the shipped mirth.properties and dynamic-lookup.properties are updated to match. A gateway configured with a jdbc:jtds: URL still has to be updated by hand; see SQL Server Driver: mssql-jdbc Upgrade + jTDS Retirement.
  • SFTP Test Connection: now reports why a directory could not be opened, instead of "Unable to connect" when authentication succeeded.
  • WebDAV connector dropped the port: webdav:// / webdavs:// connections silently ignored the configured port (forcing the default 80/443); the port is now honored, matching FTP/SFTP behavior.
  • Server-only connectors (Administrator): the Administrator no longer shows an error dialog at login for connectors whose settings are provided by WebAdmin; such connectors are simply absent from its type lists.
  • Non-English locale NPE (Administrator): editing a user on a JVM running under a non-English default locale no longer throws a NullPointerException in the user edit panel. (Contributed: PR #187.)
  • XML supplementary-character round trip: MirthXmlUtil now round-trips supplementary (astral-plane) characters correctly instead of corrupting them. Characters that XML cannot hold now fail serialization instead of producing malformed XML (see compatibility item 13).

⚙️ Configuration File Changes

mirth.properties

Key Default Description
webadmin.url (blank) URL of the standalone WebAdmin console, served by the new /webadmin-url endpoint.
password.enforceatlogin true Check stored passwords against the password policy at login and prompt a non-compliant user to change it.
password.restrictgracesessions false When enabled, a session that logged in with a non-compliant password may only change its own password until it is rotated.
server.defaultencoding (commented out) Charset used by connectors whose Encoding is "Default". Takes precedence over the legacy alias ca.uhn.hl7v2.llp.charset. Invalid values are logged at ERROR and ignored.
  • SQL-Server-backed installs must update database.url / database.driver from the jTDS form to the mssql-jdbc form before starting 26.9; see the mssql-jdbc section above.
  • Derby installs: keep upgrade=false at the end of database.url; see the Java 21 section above.

dbdrivers.xml

  • The "SQL Server / Sybase (jTDS)" driver entry is removed.

Downloads

OS Arch Download Link
Windows x64 Installer
Windows x64 MSI
Windows x64 Zip
Linux x64 RPM
Linux x64 Tar.gz
Linux x64 Installer
macOS ARM (Apple Silicon) Installer
macOS ARM (Apple Silicon) Tar.gz

The installers do not include Java. See Java 21 and the Built-in Derby Database for the runtime you need on the host.

BridgeLink CLI Downloads

The command-line client (blcommand) is packaged separately. A CLI only works against a server of the same version, so use the 26.9.0 CLI with a 26.9.0 server.

OS Arch Download Link
Windows x64 Zip
Linux x64 Tar.gz
macOS ARM (Apple Silicon) Tar.gz

🌐 BridgeLink WebAdmin

BridgeLink WebAdmin, the modern browser-based administration console and replacement for the legacy Java Swing administrator, continues to advance alongside the engine. It runs as a lightweight Node.js server and requires no Java runtime and no per-workstation install: point any modern browser (Chrome, Edge, Firefox, Safari) at it and log in with your existing BridgeLink credentials. The new Core API surface in this release (script validation, datatype defaults, connector defaults, cron/template preview) is what the console builds on.

BridgeLink WebAdmin requires a BridgeLink server running 26.3.0 or newer. The legacy Java Swing administrator remains fully supported, and both clients can be used against the same server, so you can adopt WebAdmin at your own pace.

Full documentation, Docker deployment (innovarhealthcare/bridgelink-webadmin), and source: github.com/Innovar-Healthcare/BridgeLink-WebAdmin

WebAdmin Downloads

OS Arch Download Link
Windows x64 Installer
Linux x64 Tar.gz

Prefer Docker? docker pull innovarhealthcare/bridgelink-webadmin:latest