App Suite Releases
  • 8.47
  • 8.35
  • 7.10.6
Imprint
  • 8.47
  • 8.35
  • 7.10.6
Imprint
  • Release 8.52Upcoming
  • Release 8.51
  • Release 8.50
    • Noteworthy Changes
      • Important Changes
      • App Suite Middleware
    • Changelogs
      • App Suite UI
      • App Suite Middleware
      • Additional Components
        • AI Service
        • OX Guard UI
        • Switchboard
    • Helm Charts
      • AI-Service documentation
      • App Suite Stack Chart
      • Helm Chart core-cacheservice
      • Helm Chart core-documentconverter
      • Helm Chart core-imageconverter
      • core-mw
      • Switchboard
  • Release 8.49
  • Release 8.48
  • Release 8.47LTS
  • Release 8.46
  • Release 8.45
Maintained. Older releases are best effort.
Upcoming
Not released yet
LTS
Long-term support branch

App Suite Middleware

8.50.169

3rd Party Libraries/License Change

SCR-1780

Summary: Upgraded Apache CXF to 4.2.2 and Metro JAX-WS runtime to 4.0.5

Effective: applies to the 8.50 release line

Upgraded the SOAP stack embedded in the com.openexchange.soap.common bundle:

  • 11 cxf-* libraries upgraded from 4.0.7 to 4.2.2

  • jakarta.xml.ws-api-3.0.1.jar upgraded to jakarta.xml.ws-api-4.0.3.jar

  • jaxws-rt-3.0.2.jar (Metro) upgraded to jaxws-rt-4.0.5.jar

  • saaj-impl-2.0.1.jar upgraded to saaj-impl-3.0.6.jar

  • neethi-3.2.1.jar upgraded to neethi-3.2.2.jar, xmlschema-core-2.3.1.jar to xmlschema-core-2.3.2.jar, gmbal-api-only-4.0.3.jar to gmbal-api-only-4.1.2.jar, mimepull-1.9.15.jar to mimepull-1.11.0.jar, streambuffer-2.0.2.jar to streambuffer-2.1.0.jar

The legacy javax.xml.ws compatibility libraries stay unchanged.

SCR-1774

Summary: Upgraded Hazelcast library to 5.7.0

Effective: applies to the 8.50 release line

Upgraded third-party library embedded in the com.hazelcast bundle:

  • hazelcast-5.3.8.jar upgraded to hazelcast-5.7.0.jar

Note for operators: Hazelcast Open Source does not support rolling upgrades across minor versions. During a deployment upgrade, middleware nodes running 5.7.0 will form a separate cluster from remaining 5.3.8 nodes until the rollout completes; cluster-wide volatile data (e.g. sessions held in Hazelcast maps) follows the usual full-cluster-upgrade semantics.

SCR-1773

Summary: Upgraded OWASP ESAPI library to 2.7.0.0

Effective: applies to the 8.50 release line

Upgraded third-party library embedded in the com.openexchange.common bundle:

  • esapi-2.0.1.jar upgraded to esapi-2.7.0.0.jar

Only the org.owasp.esapi.codecs package is consumed by the middleware (HTML entity decoding in com.openexchange.html); the new transitive dependency tree of the unused ESAPI reference implementation (antisamy, batik, httpclient) is excluded from the bundle.

SCR-1772

Summary: Upgraded Box Java SDK to 4.16.4

Effective: applies to the 8.50 release line

Upgraded third-party libraries embedded in the com.openexchange.file.storage.boxcom bundle:

  • box-java-sdk-2.54.0.jar upgraded to box-java-sdk-4.16.4.jar (latest release of the classic com.box.sdk API line; the 10.x line is a different, generated SDK with a new API)
  • jose4j-0.5.5.jar upgraded to jose4j-0.9.4.jar
  • zstd-jni-1.5.7-2.jar newly embedded (response decompression support of the SDK)

The SDK now performs HTTP via OkHttp, which is consumed from the com.squareup.okhttp3 platform bundle; that bundle additionally exports the kotlin base package. File thumbnails are retrieved through the file representations endpoint, as the SDK removed the legacy thumbnail API.

SCR-1771

Summary: Upgraded Dropbox Core SDK to 8.0.1

Effective: applies to the 8.50 release line

Upgraded third-party library embedded in the com.openexchange.oauth.dropbox bundle:

  • dropbox-core-sdk-3.1.5.jar upgraded to dropbox-core-sdk-8.0.1.jar

SCR-1770

Summary: Upgraded Apache XML-RPC libraries to 6.1.0

Effective: applies to the 8.50 release line

Upgraded third-party libraries embedded in middleware bundles:

  • com.openexchange.parallels: xmlrpc-client-5.0.0.jar, xmlrpc-common-5.0.0.jar, xmlrpc-server-5.0.0.jar upgraded to 6.1.0; ws-commons-util-1.0.2.jar upgraded to ws-commons-util-1.1.0.jar
  • com.openexchange.eas.provisioning.action.sms: xmlrpc-client-5.0.0.jar, xmlrpc-common-5.0.0.jar upgraded to 6.1.0; ws-commons-util-1.0.2.jar upgraded to ws-commons-util-1.1.0.jar

SCR-1769

Summary: Upgraded lib-recur library to 0.17.1

Effective: applies to the 8.50 release line

Upgraded third-party library embedded in the com.openexchange.chronos.common bundle:

  • lib-recur-0.10.jar upgraded to lib-recur-0.17.1.jar
  • jems2-2.23.1.jar newly embedded (required by lib-recur 0.17)

The recurrence rule expansion engine (org.dmfs.rfc5545.recur) is updated to the latest upstream release. The legacy recurrence-set helper classes that upstream removed in favor of a redesigned API are retained as sources in the bundle, so the iteration behavior of the calendar recurrence service is unchanged (verified by the full recurrence test suite, 50000+ tests).

SCR-1768

Summary: Upgraded ez-vcard library to 0.12.2

Effective: applies to the 8.50 release line

Upgraded third-party library embedded in the com.openexchange.contact.vcard.impl bundle:

  • ez-vcard-0.10.6.jar upgraded to ez-vcard-0.12.2.jar

The vCard date mappings were adopted to the library's new java.time-based API. Date properties (BDAY, ANNIVERSARY) are now handled as LocalDate without the former local-timezone adjustment workarounds; the serialized vCard output is unchanged.

SCR-1767

Summary: Upgraded ROME, jaudiotagger, Caffeine, MaxMind GeoIP2 and libphonenumber libraries

Effective: applies to the 8.50 release line

Upgraded third-party libraries embedded in middleware bundles:

  • com.openexchange.rss: rome-1.19.0.jar upgraded to rome-2.1.0.jar, rome-utils-1.19.0.jar upgraded to rome-utils-2.1.0.jar (rome-fetcher stays at 1.19.0, no 2.x release exists)
  • com.openexchange.server: jaudiotagger-2.2.5.jar upgraded to jaudiotagger-3.0.1.jar
  • com.openexchange.oauth.provider.impl: caffeine-2.8.5.jar upgraded to caffeine-3.2.4.jar
  • com.openexchange.geolocation.maxmind.binary: geoip2-2.17.0.jar upgraded to geoip2-5.1.0.jar, maxmind-db-2.1.0.jar upgraded to maxmind-db-4.1.0.jar
  • com.openexchange.sms: libphonenumber-8.13.1.jar upgraded to libphonenumber-9.0.34.jar

SCR-1766

Summary: Upgraded webauthn-server-core, reactor-core and zero-allocation-hashing libraries

Effective: applies to the 8.50 release line

Upgraded third-party libraries embedded in middleware bundles:

  • com.openexchange.webauthn: webauthn-server-core-2.5.3.jar upgraded to webauthn-server-core-2.9.0.jar, yubico-util-2.5.3.jar upgraded to yubico-util-2.9.0.jar
  • io.lettuce: reactor-core-3.6.6.jar upgraded to reactor-core-3.8.6.jar
  • net.openhft.hashing: zero-allocation-hashing-0.16.jar upgraded to zero-allocation-hashing-2026.0.jar

SCR-1765

Summary: Upgraded BouncyCastle libraries to 1.84 in target platform

Effective: applies to the 8.50 release line

Upgraded BouncyCastle libraries in target platform (com.openexchange.bundles):

  • bcmail-jdk18on-1.79.jar upgraded to bcmail-jdk18on-1.84.jar
  • bcpg-jdk18on-1.79.jar upgraded to bcpg-jdk18on-1.84.jar
  • bcpkix-jdk18on-1.79.jar upgraded to bcpkix-jdk18on-1.84.jar
  • bcprov-jdk18on-1.79.jar upgraded to bcprov-jdk18on-1.84.jar
  • bcutil-jdk18on-1.79.jar upgraded to bcutil-jdk18on-1.84.jar

BouncyCastle 1.84 removed the legacy post-quantum algorithm packages org.bouncycastle.pqc.crypto.rainbow, org.bouncycastle.pqc.jcajce.provider.gmss and org.bouncycastle.pqc.jcajce.provider.mceliece; stale (unused) imports of these packages were removed from the com.openexchange.saml bundle manifest. The OpenPGP API change of PGPKeyEncryptionMethodGenerator.generate(...) was adopted in com.openexchange.pgp.core (wire format of generated PKESK packets is unchanged).

SCR-1762

Summary: Upgraded Liquibase to v5.0.3

Effective: applies to the 8.50 release line

Upgraded the embedded database migration engine in the encapsulated liquibase.core wrapper bundle:

  • liquibase-core-4.33.0.jar upgraded to liquibase-core-5.0.3.jar
  • opencsv-5.11.2.jar upgraded to opencsv-5.12.0.jar

Liquibase 5.0.x is a major release, but the exported package set and external dependency surface are identical to 4.33.0, so Export-Package/Import-Package stay structurally unchanged. The in-house Liquibase extensions in com.openexchange.database.migration (custom ChangeLogHistoryService, XML changelog parser, preconditions, SLF4J logging) compile and pass their tests against the 5.0.3 SPIs without source changes.

Checksum stability was verified end-to-end against MariaDB: a DATABASECHANGELOG populated with legacy checksums is recognized as already-applied and left untouched (no changeset re-execution), preserving rollback compatibility.

8.50.165

General

SCR-1803

Summary: New properties for the replication monitor's replica status check

Effective: 8.50.165 and later

The replication monitor now probes read replicas' replication status (SHOW SLAVE STATUS) and redirects reads to the master while a replica reports broken replication or excessive lag. This closes the gap that a re-seeded or inconsistently restored replica could serve incomplete data undetected (middleware/core#4, follow-up to the incident behind appsuite/support#1599). Four new lean configuration properties control the behavior:

  • com.openexchange.database.replicationMonitor.checkReplicaStatus (default: true) - Whether to watch read replicas for broken or excessively lagging replication and redirect reads to the master meanwhile. Works out of the box: where the REPLICA MONITOR (MariaDB) or REPLICATION CLIENT (MySQL) privilege is available, the replication status statement provides fast, precise detection; without it the check falls back to a privilege-free heartbeat, a time stamp periodically written through the replication channel into the replicationMonitor table (reserved row cid=4294967295), needing only the regular INSERT/UPDATE/SELECT permissions. REPLICA MONITOR (MariaDB) or REPLICATION CLIENT (MySQL) privilege; both are global privileges, so one grant per database host covers all existing and future schemas, and initconfigdb -a now grants them automatically. Without the privilege the check suspends itself for the affected pool. Only effective if the replication monitor is active. Default: true. Reloadable: false. Config-cascade aware: false.
  • com.openexchange.database.replicationMonitor.maxReplicaLag - Maximum tolerated replication lag in seconds before reads are redirected to the master. Default: 300. Reloadable: false. Config-cascade aware: false.
  • com.openexchange.database.replicationMonitor.replicaStatusCheckInterval - Minimum number of seconds between two replication status probes per read pool. Default: 10. Reloadable: false. Config-cascade aware: false.
  • com.openexchange.database.replicationMonitor.requireReplication - Whether a read host that does not act as a replica at all (empty SHOW SLAVE STATUS) is considered unhealthy. Keep false for Galera or multi-primary setups; set to true where read pools are always asynchronous replicas. Default: false. Reloadable: false. Config-cascade aware: false.

All four properties are read once at middleware start-up; changing them requires a restart. They are server-scoped (no config-cascade evaluation) and documented in documentation-generic/config/ConfigDB.yml. Defaults are safe for every topology: without the privilege or without asynchronous replication the check fails open and behavior is unchanged.

8.50.164

3rd Party Libraries/License Change

SCR-1749

Summary: Upgraded Grizzly to 5.0.2

Effective: 8.50.164 and later

Upgraded the encapsulated Grizzly libraries in the com.openexchange.http.grizzly PDE bundle:

  • grizzly-http-all-5.0.1.jar upgraded to grizzly-http-all-5.0.2.jar
  • grizzly-framework-monitoring-5.0.1.jar upgraded to grizzly-framework-monitoring-5.0.2.jar
  • grizzly-http-monitoring-5.0.1.jar upgraded to grizzly-http-monitoring-5.0.2.jar
  • grizzly-http-server-monitoring-5.0.1.jar upgraded to grizzly-http-server-monitoring-5.0.2.jar

Resolved transitive shifts: gmbal/gmbal-api-only 4.1.1 -> 4.1.2, pfl-* 5.1.0 -> 5.1.1 (management-api unchanged at 3.3.0). No new or removed embedded dependencies.

Code adaptation

Grizzly 5.0.2 replaces the HttpResponsePacket acknowledgement API (setAcknowledgement()/acknowledged()) with an interim-response model (setInterimStatus()/interimResponseSent(), also covering 103 Early Hints). The custom codec filter (CustomHttpCodecFilter), which sends the 100 Continue interim response at header-parse time, now sets the interim status and lets the codec serialize the status line instead of hand-building the bytes. The wire format is unchanged (HTTP/1.1 100 Continue).

Behavioral change: strict RFC 9110 header validation enabled by default

Grizzly 5.0.2 enables strict RFC 9110 validation of HTTP header names (token rules) and header values (field-content rules) by default. Requests carrying malformed header names/values are now rejected with 400 Bad Request during parsing (hardening against request smuggling).

New configuration properties

The validation switches are exposed as lean OX configuration properties (no .properties file entry, read on server start):

  • com.openexchange.http.grizzly.strictHeaderNameValidation (default: true)
  • com.openexchange.http.grizzly.strictHeaderValueValidation (default: true)

Setting a property to false restores the former lenient parsing for legacy clients. The OX properties are authoritative for the HTTP server codec and take precedence over the Grizzly JVM system properties org.glassfish.grizzly.http.STRICT_HEADER_NAME_VALIDATION_RFC_9110 / org.glassfish.grizzly.http.STRICT_HEADER_VALUE_VALIDATION_RFC_9110.

8.50.152

General

SCR-1800

Summary: New property to obtain IMAP subscription state from separate LSUB when the \Subscribed attribute of LIST-EXTENDED responses is untrustworthy

Effective: 8.50.152 and later

Motivation

On IMAP servers advertising the LIST-EXTENDED capability (RFC 5258), the middleware determines mailbox subscriptions from the single consolidated command LIST "" "*" RETURN (SUBSCRIBED CHILDREN [SPECIAL-USE]). Certain proxy setups (e.g. Dovecot with an imapc backend, see /appsuite/support#1543 and DOP-3897) answer the SUBSCRIBED return option inconsistently with LSUB: subscribed mailboxes in shared/user namespaces are listed without the \Subscribed attribute, so subscriptions to shared folders never become visible in App Suite.

Change

New lean configuration property (no .properties file entry):

  • Key: com.openexchange.imap.considerSubscribedInListExtended
  • Default: true (unchanged behavior)
  • Reloadable: yes; config-cascade aware: no (server scope)

Supported values:

  • true: trust the attribute; subscription state comes from the single consolidated round-trip (behavior as before).

  • false: hybrid mode; the consolidated command (without SUBSCRIBED) still provides hierarchy, children and special-use information, while a separate LSUB "" "*" provides the subscription state.

  • probe: verify once per IMAP server whether the attribute matches LSUB output and cache the verdict per server (lifetime governed by com.openexchange.imap.cache.commonImapServerCacheTimeToLive). A probe is only conclusive if it either finds a mismatch or covers at least one subscribed mailbox inside a shared/user namespace; otherwise no verdict is cached and the next folder-cache initialization probes again. A probe run costs no additional IMAP round-trip compared to hybrid mode.

The property only takes effect on servers advertising LIST-EXTENDED; without that capability separate LIST/LSUB commands are issued anyway.

Operator action

None by default. Set the property to false (or probe) for installations whose IMAP server/proxy reports the \Subscribed attribute of the consolidated LIST command unreliably.

8.50.140

General

SCR-1793

Summary: Redis connector: per-node client name, max. connection lifetime, deterministic shutdown

Effective: 8.50.140 and later

Hardening of the Redis connector against stale / orphaned connected clients.

New configuration option:

  • com.openexchange.redis.connection.pool.maxLifetimeSeconds Maximum lifetime in seconds of a pooled Redis connection. Once a connection exceeds this age it is proactively recycled by the connection-pool cleaner as soon as it becomes idle, regardless of usage; this applies to both the shared and the dedicated pool. Acts as defense-in-depth against slowly accumulating or long-lived stale connections that TCP keepalive cannot reap (a live-but-idle connection is never detected as dead). A value of 0 (zero) disables max. lifetime recycling. Default 3600 (one hour). Not reloadable, not config.cascade aware. Package: open-xchange-core.

Behavioral changes (no configuration):

  • Client name: the announced Redis client name now includes the local host / pod name (e.g. Open-Xchange-Redis-Connector-v8.53.0-<host>), so connections become attributable per node via Redis CLIENT LIST. This is what lets operators tell restart orphans (dead pod addresses) apart from live-node connections.
  • Deterministic shutdown: the shared connection pool now closes its connections synchronously on shutdown, so Redis reclaims the clients immediately on a graceful (rolling) restart instead of leaving them as ghosts.

8.50.121

API - REST

SCR-1714

Summary: New Administrative REST Servlet for Shared Accounts

Effective: 8.50.121 and later

Permissions and capabilities a particular user effectively has for a shared account are not persisted as such, but evaluated dynamically at runtime - based on the base configuration and all shared account permissions the user received, directly as well as indirectly through his group memberships. Since this calculated result can therefore not be deduced directly from the provisioned data, a dedicated administrative REST interface is available that answers the question: which effective permissions and capabilities does a certain user have for a shared account?

The endpoints are exposed below /preliminary/sharedaccounts/v1 and are protected via HTTP Basic Authentication, with the credentials configured through the properties com.openexchange.rest.services.basic-auth.login and com.openexchange.rest.services.basic-auth.password.

The user whose access is to be evaluated - and, where applicable, the targeted shared account - can be referenced in three alternative ways: by their explicit internal identifiers, by their email address, or by their mail login string.

See the general documentation, as well as the REST API documentation for further details.

8.50.114

General

SCR-1708

Summary: Grizzly 5.0.1 + jakarta.servlet 6.1 introduction; CXF 4, JAX-WS RT 3, Angus Activation pulled in

Effective: 8.50.114 and later

  • OSGi HTTP stack lifted to Jakarta Servlet 6.1
  • Grizzly upgraded to 5.0.1 (JDK 21 baseline, virtual threads support)
  • Grizzly HTTP filter chain (WrappingFilter, RequestReportingFilter, wrappers) runs natively on jakarta.servlet — no more javax↔jakarta bridging at the filter level.
  • A parallel javax-servlet surface is kept alive via an in-process bridge so existing bundles and external consumers (Guard, OEM) continue to work unchanged.

Library updates

|| Library || Old || New || | Eclipse Grizzly | 2.4.4 | 5.0.1 | | Apache CXF | 3.5.11 | 4.0.7 | | Sun/Glassfish JAX-WS RT | 2.x | 3.0.2 | | Jolokia | 1.x | 2.x | | jakarta.servlet-api | — | 6.1.0 | | jakarta.xml.ws-api | — | 3.0.1 | | jakarta.jws-api | — | 3.0.0 | | jakarta.xml.bind-api | — | 3.0.1 | | jakarta.xml.soap-api | — | 3.0.2 | | jakarta.activation-api | — | 2.1.3 | | jakarta.annotation-api | — | 2.1.1 | | Eclipse Angus Activation (jakarta.activation SPI impl) | — | 2.0.2 | | gmbal | 4.0.3 | 4.1.1 | | management-api | 3.2.3 | 3.3.0 | | pfl-* | 4.1.2 | 5.1.0 |

Scope

  • com.openexchange.http.grizzly ported to Grizzly 5.0.1 / jakarta-servlet 6.1. Filter chain and servlet wrappers run natively on jakarta.servlet.
  • HttpServletRequestWrapper implements Holders.RequestHolder for direct Grizzly Request access.
  • RequestWatcherService converted to jakarta.servlet types.
  • ASM JARs removed from Grizzly bundle (resolved from target platform via Import-Package).
  • New bridge bundle com.openexchange.servlet.bridge adapts javax↔jakarta requests/responses in both directions, enabling a gradual migration.
  • 11 SOAP stub bundles (com.openexchange.admin.soap.{context,deputy,group,reseller,resource,secondaryaccount,sharedaccount,taskmgmt,user,usercopy,util}) plus com.openexchange.sessiond.soap and openexchange-test migrated to jakarta.xml.ws / jakarta.jws.
  • DAV/CalDAV/CardDAV, Prometheus exporter, Jolokia and R8 whiteboard servlets now use jakarta-servlet natively.
  • Existing javax-servlet consumers keep running via the bridge.

Compatibility

No breaking changes for external RMI/SOAP consumers. External plug-ins that reference javax.servlet wrapper classes directly need no changes — the javax.servlet 4.0 Import-Package surface is preserved.

8.50.112

API - HTTP-API

SCR-1711

Summary: Added new cluster-internal REST endpoint to validate Middleware sessions for the JMAP-IMAP proxy

Effective: 8.50.112 and later

Motivation

The HTTP/REST API previously had no entry point that lets the cluster-internal JMAP-IMAP proxy resolve a user's Middleware session into the IMAP backend coordinates and credentials it needs to forward JMAP calls. Standalone JMAP clients can authenticate against the proxy directly via HTTP Basic / OIDC -- the App Suite UI cannot, because it only carries a Middleware session cookie.

This SCR closes that gap with a dedicated cluster-internal REST endpoint, hardened against credential exposure.

New Endpoint
  • Method + path: GET /preliminary/mail/v1/validate-session/<session>
  • Bundle: com.openexchange.mail.rest (new), registered via open-xchange-core.psf
  • Required path parameter: session -- the Middleware session identifier (length-capped to 128 chars)
  • Required header: X-OX-Session-Secret -- the plain value of the user's open-xchange-secret-<hash> cookie, forwarded by the proxy from the originating client request (length-capped to 512 chars)
  • HTTP Basic-Auth: gated by Role.BASIC_AUTHENTICATED (cluster-internal REST credentials com.openexchange.rest.services.basic-auth.*; identical to SessionRESTService)

The session is resolved in a touch-free manner via SessiondService.peekSession(String); repeated polling does not reset the session's idle expiration counter, so the proxy can poll at ~30 s without keeping otherwise idle sessions alive.

Response: AES-256-GCM Envelope

Because the response carries the user's plaintext mail password (LOGIN flow) / OAuth access token plus internal infrastructure details (IMAP host name, login, primary email), the entire success body is wrapped in an AES-256-GCM envelope.

Wire format on HTTP 200:

{
  "v": 1,
  "envelope": "v1:<base64-iv>:<base64-ct-with-tag>"
}

The ciphertext decodes to the inner payload:

{
  "identity": { "user", "context", "displayName", "primaryEmail" },
  "imap":     { "host", "port", "secure" },
  "auth":     { "type", "loginName", "secret", "secretExpiresInSeconds" },
  "session":  { "expiresInSeconds" }
}

auth.type ∈ `{LOGIN, XOAUTH2, OAUTHBEARER\}, mirroring the Middleware-internal AuthType` enum.

A fresh 12-byte random IV is generated per call. The caller's Basic-Auth identity (UTF-8 bytes) is additionally bound into the GCM authentication tag via Associated Authenticated Data, so an envelope captured from one caller cannot be successfully decrypted with a different caller's credentials. The proxy must pass the byte-identical AAD when decrypting; the wire format itself remains unchanged.

Error responses (401/403/429/503/500) are plaintext OX-error-JSON so the proxy can forward them to the originating client untouched.

Example request:

GET /preliminary/mail/v1/validate-session/abc123def456
Authorization: Basic <base64 of proxy credentials>
X-OX-Session-Secret: <secret cookie value>
Authentication

The endpoint enforces two independent authentication layers:

  • Authorization Basic-Auth gates the caller (proves "you're the JMAP-IMAP proxy"). Cluster-internal credentials, same pool as other internal REST endpoints.
  • X-OX-Session-Secret compared against session.getSecret() in constant time (via MessageDigest.isEqual) so the comparison's running time does not leak information about which bytes already matched. Prevents resolving arbitrary session identifiers -- the caller must have seen the user's actual cookies, otherwise the lookup fails.

After 5 consecutive secret-mismatch attempts on the same session identifier within a 10-minute window, the session itself is invalidated cluster-wide via SessiondService.removeSession(..., ADMIN_CLOSED). A legitimate proxy call never produces a mismatch, so the threshold cannot fire on real traffic.

Sessions whose OAuth access-token expiry (Session.PARAM_OAUTH_ACCESS_TOKEN_EXPIRY_DATE) is in the past are rejected upfront with SES-0203 rather than handed out as a dead token.

Error Handling
  • HTTP 401 (Basic-Auth missing/invalid) -- handled by the REST stack before the resource method runs.
  • HTTP 401 with OX error JSON (SES-0203 SESSION_EXPIRED) -- raised on unknown / expired sessions, missing / mismatching X-OX-Session-Secret, or expired OAuth tokens. The OXException chain matches SessionUtility.checkSecret byte-for-byte (OXEXCEPTION_PROPERTY_SESSION_EXPIRATION_REASON carries NO_SUCH_SESSION, NO_EXPECTED_SECRET_COOKIE or SECRET_MISMATCH), so the proxy can forward the resulting error JSON to the originating client untouched and the standard SES-0203 handling kicks in.
  • HTTP 403 with OX error JSON (MAIL-0114 MAIL_ACCESS_DISABLED) -- raised when the user has no primary mail account or the primary account is disabled.
  • HTTP 403 -- raised when TLS is required (com.openexchange.mail.rest.requireTls=true, default) and the request is not secure, or when the source IP is not contained in the configured allowlist (com.openexchange.mail.rest.allowedSourceIPs).
  • HTTP 429 (empty body) -- raised when a Basic-Auth identity exceeds 6 000 requests per minute. The proxy should treat this as a load signal and back off exponentially; do not forward to the originating client.
  • HTTP 503 with OX error JSON -- raised when the server-side AES-256 encryption key is missing or invalid. Fails closed: the endpoint never serves a plaintext fallback.
Operational Hardening
  • Cache-Control: no-store, no-cache, must-revalidate + Pragma: no-cache on every response so no HTTP intermediary along the in-cluster path persists the (encrypted) body.
  • Every call is audit-logged via AuditLogService with an outcome-specific event id (ox.mail.validateSession.success, ox.mail.validateSession.session-expired.<reason>, ox.mail.validateSession.mail-access-disabled, ox.mail.validateSession.error). Caller identity, session id and timestamp only; never the supplied secret value, never the user's password / token.
Configuration

The endpoint introduces a small set of properties, documented and tracked separately in SCR-1712:

  • com.openexchange.mail.rest.encryption.key (required) -- the AES-256 key shared with the JMAP-IMAP proxy
  • com.openexchange.mail.rest.requireTls (default true) -- toggle for TLS enforcement
  • com.openexchange.mail.rest.allowedSourceIPs (default empty) -- optional source-IP allowlist

The endpoint additionally reuses:

  • com.openexchange.rest.services.basic-auth.login / .password -- the cluster-internal REST credentials (shared with the other Role.BASIC_AUTHENTICATED endpoints)
  • com.openexchange.sessiond.sessionDefaultLifeTime / sessionLongLifeTime -- session lifetime estimation

SCR-1695

Summary: New Action 'hasActive' in Module 'mailfilter/v2'

Effective: 8.50.112 and later

In order to get a quick information if there are currently specific mail filter rules active or not for an account, the new action hasActive is introduced in module mailfilter/v2 of the HTTP API.

See the API documentation for further details.

SCR-1692

Summary: Additional Field 'com.openexchange.imap.rootFolderStatus' for Mail Account Root Folders

Effective: 8.50.112 and later

The folder model (FolderResponseData) of the HTTP API is extended by the additional read-only field com.openexchange.imap.rootFolderStatus (column id 3053). It is only available for the special, virtual mail account root folders (e.g. with if default0 or default14), if supported by the underyling IMAP server.

It contains information about the data within the mail account as JSON object - which currently is a simple overall containsUnread flag that is true whenever there is an unseen message within any of the contained mail folders.

See the documentation for further details.

Configuration

SCR-1696

Summary: New Configuration Property 'com.openexchange.mail.filter.options.vacation.minimumInterval.seconds'

Effective: 8.50.112 and later

A new property com.openexchange.mail.filter.options.vacation.minimumInterval.seconds has been introduced to allow configuring the minimum interval for seconds-based vacation Sieve rules.

When set to -1 (default), the use of seconds-based vacation rules is disabled. Any positive value defines the minimum number of seconds that must elapse between automated vacation responses sent to the same sender.

This property only takes effect if the IMAP server advertises the vacation-seconds capability.

See the [property documentation](https://documentation.open-xchange.com/components/middleware/config/8/#mode=search&term=com.openexchange.mail.filter.secondary.) for further details.

8.50.108

Configuration

SCR-1713

Summary: New and changed configuration defaults for database connection pool admission control, worker thread pool, and health check

Effective: 8.50.108 and later

New and changed configuration defaults to prevent thundering-herd death spirals during Kubernetes autoscaler scale-up events (see support#1477 and core#520).

Connection pool admission control

  • maxWaiting Maximum number of threads allowed to wait for a database connection when the pool is exhausted and exhaustedAction is set to BLOCK. If this limit is reached, additional requests fail immediately with an exception instead of blocking. This prevents unbounded thread accumulation during load spikes (e.g. cold-cache stampedes after autoscaler scale-up events). A value of -1 means unlimited (no cap on waiting threads). Shipped default 400 (4x maxActive); set -1 to restore the previous unlimited behavior. Not reloadable, not config-cascade aware. File: configdb.properties.

Database pool readiness health check

Two properties control a new database-pool health check that is wired into the /ready readiness endpoint. When the check reports DOWN, Kubernetes stops routing traffic to the pod.

  • com.openexchange.database.health.poolUtilizationThreshold The database connection pool utilization percentage (0-100) at or above which the readiness health check reports DOWN. Default 90. Not reloadable, not config-cascade aware. File: configdb.properties.

  • com.openexchange.database.health.maxWaitingThreshold The maximum number of threads waiting for a database connection above which the readiness health check reports DOWN. Default 500. Not reloadable, not config-cascade aware. File: configdb.properties.

8.50.96

Configuration

SCR-1712

Summary: New configuration options for the validate-session REST endpoint

Effective: 8.50.96 and later

New configuration options for the cluster-internal validate-session REST endpoint (see SCR-1711)

  • com.openexchange.mail.rest.encryption.key Shared secret string from which the AES-256 key for wrapping the validate-session response body (identity, IMAP coordinates, credentials) in an AES-256-GCM envelope is derived. The byte-identical secret must be provisioned on the JMAP-IMAP proxy side so the proxy can derive the same key, decrypt the response, and recover the IMAP backend coordinates plus the user's plaintext password / OAuth access token. <b>Key derivation</b>: the configured value is trimmed and then hashed once with SHA-256 over its UTF-8 bytes; the 32-byte digest is the AES-256 key. The proxy must reproduce this derivation exactly. No salt and no iteration count are involved, so the secret itself must carry enough entropy (a long random string, not a passphrase). Minimum length is 16 characters after trimming; shorter values are rejected fail-closed. Generate a fresh secret via e.g. openssl rand -hex 32 (64 hex chars) or pwgen -s 64 1; use a different secret per environment; rotate it independently of the SessionD encryption key and the cluster-internal REST basic-auth password. The caller's Basic-Auth identity is bound into the GCM tag as Associated Authenticated Data, so an envelope captured from one caller cannot be decrypted with another caller's credentials. <b>Fail-closed</b>: if the property is unset, blank, or shorter than the minimum length, the endpoint responds with HTTP 503 instead of returning a plaintext payload. No default. Not reloadable, not config.cascade aware.

  • com.openexchange.mail.rest.requireTls Whether the validate-session REST endpoint rejects non-TLS requests with HTTP 403. Defaults to true (fail-secure) so that even an accidental plain-HTTP route to the endpoint cannot expose the encrypted-but-still-sensitive validate-session payload. Set to false only in deployments where the in-cluster path from the JMAP-IMAP proxy to the Middleware is known to be plain-HTTP by design (e.g. when TLS is terminated upstream of the Middleware container and the request is delivered via cleartext within a trusted pod network). Default true. Reloadable, not config.cascade aware.

  • com.openexchange.mail.rest.allowedSourceIPs Optional comma-separated allowlist of source addresses permitted to call the validate-session REST endpoint. When set, only requests originating from one of the listed addresses are accepted; everything else is rejected with HTTP 403 before any further processing. The value is parsed via com.openexchange.net.HostList and therefore supports individual IP addresses, CIDR ranges (e.g. 10.42.0.0/16, 2001:db8::/32), and host names. Defaults to empty, meaning no allowlist filter is applied. Defense-in-depth on top of the cluster-internal ingress restriction that already keeps /preliminary/* off the public network. Example: 10.42.0.0/16, 192.168.1.100. No default. Reloadable, not config.cascade aware.

8.50.90

API - HTTP-API

SCR-1710

Summary: Added new HTTP-API end-point to fetch a mail by its GUID

Effective: 8.50.90 and later

Motivation

The HTTP API currently only allows resolving a mail via its (folder, UID) tuple. For clients that hold a globally unique identifier (GUID) advertised by the mail backend (such as Dovecot's X-GUID attribute), no entry point exists. This SCR introduces a new read-only AJAX action that performs a GUID-based look-up.

New Action
  • Module: mail
  • Action: getByGuid
  • Method: GET
  • Required parameter: guid — the GUID as advertised by the mail backend
  • Optional parameter: folder — restricts the look-up to that folder; when omitted, the action queries the virtual "all messages" mailbox configured via property com.openexchange.find.basic.mail.allMessagesFolder
  • Response: MailResponse} (same payload as action=get); for cross-folder look-ups the response carries original_folder_idandoriginal_id` to identify the source folder.

Example:

GET /ajax/mail?action=getByGuid&guid=deadbeefcafe1234&session=...
GET /ajax/mail?action=getByGuid&guid=deadbeefcafe1234&folder=default0/INBOX&session=...
Capability Gating

The action requires the underlying mail backend to advertise GUID support. If the backend does not support it, or if cross-folder look-up is requested but com.openexchange.find.basic.mail.allMessagesFolder`` is empty, the request fails with MAIL_FILESTORE-0030 (UNSUPPORTED_OPERATION`).

If no mail matches the supplied GUID, the request fails with MAIL-0032 (MAIL_NOT_FOUND).

Configuration

No new properties are introduced. The existing property com.openexchange.find.basic.mail.allMessagesFolder (already used by the Find module) gates the cross-folder code path.

8.50.77

Configuration

SCR-1706

Summary: New configuration options for externalizing data: URL inline images

Effective: 8.50.77 and later

New lean configuration options for externalizing data: URL inline images

  • com.openexchange.html.inlineDataUrls.extract Whether data: URL inline images embedded in an HTML mail body shall be externalized into managed-file body parts and replaced with cid: references before the HTML size check (com.openexchange.html.maxLength) is applied. This avoids degrading to plain text for mails whose only oversize-cause is one or more inflated base64 inline images. Default true. Reloadable, but not config.cascade aware.

  • com.openexchange.html.inlineDataUrls.minPartSize Minimum size in bytes of a decoded data: URL inline image to qualify for externalization. Smaller payloads (e.g. tiny tracking pixels) are left in place because the synthetic body part overhead would outweigh the savings. Default 4096. Reloadable, but not config.cascade aware.

  • com.openexchange.html.inlineDataUrls.maxPartSize Maximum size in bytes of a single decoded data: URL inline image. Larger payloads are left in place; the regular HTML size check then governs whether the mail is rendered as HTML or as plain text. Default 26214400. Reloadable, but not config.cascade aware.

  • com.openexchange.html.inlineDataUrls.maxTotalSize Aggregate cap in bytes across all data: URL inline images that may be externalized from a single HTML body. Also used to relax the HTML size check by the same amount when extraction is enabled (relaxed cap is com.openexchange.html.maxLength + this). Default 52428800. Reloadable, but not config.cascade aware.

  • com.openexchange.html.inlineDataUrls.ttlSeconds Time-to-live in seconds for managed files that hold the bytes of extracted data: URL inline images. Must be long enough to cover the time between HTML render and the client's image fetches. On miss, the InlineImageDataSource worst-case fallback re-extracts the image from the source mail. Default 1800. Reloadable, but not config.cascade aware.

8.50.74

3rd Party Libraries/License Change

SCR-1707

Summary: Upgraded Liquibase from forked 3.0.7 to upstream 4.33.0

Effective: 8.50.74 and later

Replaced the bespoke liquibase.core/ source fork with a thin OSGi JAR-wrapper that ships the official upstream artifacts:

  • liquibase-core-4.33.0.jar
  • opencsv-5.11.2.jar

Adapter changes in com.openexchange.database.migration

  • Slf4jLogger reimplemented against liquibase.logging.Logger (severe/warning/info/config/fine/debug + log(Level,String,Throwable))
  • new Slf4jLogService registered via META-INF/services/liquibase.logging.LogService with priority 5
  • BundleResourceAccessor rewritten against the new ResourceAccessor contract (search / getAll / describeLocations, AbstractResource-backed BundleResource)
  • BundlePackageScanClassResolver removed - the old ServiceLocator-based package scan is replaced by java.util.ServiceLoader plus the OSGi activator's bundle tracking
  • DBMigrationActivator no longer sets a CustomResolverServiceLocator
  • StaleMigrationDetectingLockService switched from LogFactory to Scope.getCurrentScope().getLog(getClass())

Namespace tolerance

Added liquibase.parser.ext.UrnNamespaceTolerantXMLChangeLogParser which rewrites the legacy urn:liquibase namespace to the canonical http://www.liquibase.org/xml/ns/dbchangelog on the fly so the four existing changelog XMLs (configdbChangeLog, globaldbChangeLog, resellerConfigdbChangeLog, autocidConfigdbChangeLog) continue to parse without modifications. Registered via META-INF/services/liquibase.parser.ChangeLogParser with a +10 priority bump.

Rollback compatibility (legacy MD5SUM preservation)

To allow rollback to a pre-Liquibase-4 OX container, the DATABASECHANGELOG table must keep its version-7 checksum prefix the old fork understands. Two safety nets are in place:

  • LegacyChecksumPreservingHistoryService extends StandardChangeLogHistoryService and no-ops upgradeChecksums + replaceChecksum. Liquibase 4.x still recomputes hashes in memory and matches them with multi-algo tolerance, so legacy 7: entries continue to be recognized as already-run; only the persistence side is blocked. Registered via META-INF/services/liquibase.changelog.ChangeLogHistoryService with a +10 priority bump.
  • LiquibaseHelper.snapshotLegacyChangelogIfNeeded copies DATABASECHANGELOG into DATABASECHANGELOG_BACKUP_LQ4 on the very first 4.x boot per schema (idempotent, skipped on fresh schemas and on subsequent boots). Failures are logged, not thrown - a failed snapshot must not block the migration.

8.50.69

Database

SCR-1709

Summary: Enlarge the "meta" column from BLOB to MEDIUMBLOB for the "oxfolder_tree" and "del_oxfolder_tree" tables

Effective: 8.50.69 and later

Added new update task com.openexchange.groupware.update.tasks.EnlargeMetaForOXFolderTablesTask enlarging the "meta" column from BLOB to MEDIUMBLOB for the "oxfolder_tree" and "del_oxfolder_tree" tables

8.50.10

Configuration

SCR-1694

Summary: Added several configuration options to mitigate too many SMTP connections

Effective: 8.50.10 and later

  • com.openexchange.smtp.enablePipelining Specifies if the "PIPELINING" extension of an SMTP server should be used. Default is true. Reloadable and config-cascade aware

  • com.openexchange.smtp.pool.enabled Enables or disables the SMTP connection pool. Default is false. Reloadable and config-cascade aware

  • com.openexchange.smtp.pool.maxIdlePerKey Specifies the max. number of idle pooled SMTP connections per SMTP end-point. A vale of equal to/less than 0 (zero) means infinite. Default is 5. Reloadable and config-cascade aware

  • com.openexchange.smtp.pool.maxIdleMillis Specifies the time in milliseconds an SMTP connection may reside idle in pool before it is dropped. Default is 10000. Reloadable and config-cascade aware

  • com.openexchange.smtp.pool.maxLifetimeMillis Specifies the max. lifetime in milliseconds an SMTP connection regardless if idle or was in use. Default is 300000. Reloadable and config-cascade aware

  • com.openexchange.smtp.pool.testOnBorrow Specifies whether an SMTP connection is checked if still orderly connected when borrowed. Default is true. Reloadable and config-cascade aware

  • com.openexchange.smtp.pool.testOnReturn Specifies whether an SMTP connection is checked if still orderly connected when returned. Default is false. Reloadable and config-cascade aware

  • com.openexchange.smtp.pool.cleanupIntervalMillis Specifies the frequency to check for timed out idle SMTP connections. Default is 3500. Reloadable and config-cascade aware

  • com.openexchange.smtp.pool.maxConnectionsPerKey Specifies the max. number of total SMTP connections that are permitted for a user to a certain SMTP end-point. A vale of equal to/less than 0 (zero) means infinite. Default is 8. Reloadable and config-cascade aware

  • com.openexchange.smtp.pool.borrowWaitMillis Specifies the max. time in milliseconds to wait for an SMTP connection available in pool. Default is 5000. Reloadable and config-cascade aware

  • com.openexchange.mail.scheduled.checkAndSendDueScheduledMails The switch to allow per node/JVM to perform the check and transport of due scheduled mails. Default is true. Reloadable, but not config-cascade aware

  • com.openexchange.mail.scheduled.transport.maxNumberOfConcurrentScheduledMails The max. total number of scheduled mails (of all users) that are allowed being concurrently sent. Default is 0 (infinite). Reloadable, but not config-cascade aware

  • com.openexchange.mail.scheduled.transport.globalLimit Whether com.openexchange.mail.scheduled.transport.maxNumberOfConcurrentScheduledMails property refers to a global limit or per JVM/node only. Default is true. Reloadable, but not config-cascade aware

  • com.openexchange.mail.scheduled.transport.leaseDurationMillis The duration (or time-to-live) in milliseconds a leased transport permit is considered as valid before it times out. Default is 60000. Reloadable, but not config-cascade aware

  • com.openexchange.mail.scheduled.transport.acquireTimeoutMillis The duration in milliseconds to wait for a transport permit to become available. 0 (zero) merans to wait until a permit is available. Default is 0 (no wait). Reloadable, but not config-cascade aware

Prev
Important Changes