Skip to content

Configs with allowInsecure: true are rejected by Xray-core since 2026-06-01 — clients (Happ Plus, etc.) can no longer connect #5438

Description

@Futyn-Maker

Description

Since June 1st, 2026 my Xray-based clients stopped connecting to my own Hiddify Manager server. On Happ Plus (iOS) the moment I refresh/import the subscription I get:

common/errors: The feature "allowInsecure" has been removed and migrated to "pinnedPeerCertSha256". Please update your config(s) according to release note and documentation.

This is not a bug in Happ. The message comes straight from Xray-core. Newer Xray-core (v26.1.18+) no longer accepts the allowInsecure TLS option, and there is a hard date switch on it: before 2026-06-01 it only logged a warning, after that date it became a fatal config error. You can see it in the core itself, in TLSConfig.Build():

https://github.com/XTLS/Xray-core/blob/main/infra/conf/transport_internet.go

if c.AllowInsecure {
    if time.Now().After(time.Date(2026, 6, 1, 0, 0, 0, 0, time.UTC)) {
        return nil, errors.PrintRemovedFeatureError(`"allowInsecure"`, `"pinnedPeerCertSha256"`)
    } else {
        errors.LogWarning(context.Background(),
            `"allowInsecure" will be removed automatically after 2026-06-01, please use "pinnedPeerCertSha256"(pcs) and "verifyPeerCertByName"(vcn) instead ...`)
        config.AllowInsecure = true
    }
}

So this is a time bomb that went off for everyone at once on 2026-06-01: any client that bundles a recent Xray-core (Happ Plus did after its update) now refuses every config that contains "allowInsecure": true. Same breakage was reported in other projects that emit this flag — v2rayN (2dust/v2rayN#8736), Passwall2 (Openwrt-Passwall/openwrt-passwall2#999, Openwrt-Passwall/openwrt-passwall2#1009), 3x-ui (MHSanaei/3x-ui#3727).

The problem on the Hiddify side is that the panel puts "allowInsecure": true into every non-Reality TLS outbound of the generated xray subscription, even when the domain has a valid, publicly-trusted certificate where allowInsecure is not needed at all. In my case the domain is a normal direct domain with a valid Let's Encrypt certificate, the outbound connects to that same hostname, and serverName is that same hostname — so standard certificate verification would succeed and the flag is completely unnecessary. But it's there on all of them, and now it breaks the config.

Where I think the bug is

I dug into the panel source (I'm on 12.3.3, but I checked main/dev too and the code is identical there). As far as I can tell the value originates in sni_host_server_extractor():

https://github.com/hiddify/HiddifyPanel/blob/v12.3.3/hiddifypanel/hutils/proxy/shared.py#L324-L333

allow_insecure = not domain_db.need_valid_ssl          # for a direct/cdn/relay domain this is False (correct!)
if all_snis := split_pattern.split((domain_db.servernames or "").strip()):
    sni = random_or_none(all_snis) or sni
    if 'reality' in domain_db.mode:
        allow_insecure = False
    else:
        allow_insecure = True                          # <-- overrides it back to True

The first line computes the right value: for modes that are supposed to have a valid cert (direct, cdn, relay, etc., per need_valid_ssl in models/domain.py) it sets allow_insecure = False. The problem is the if all_snis := ... block, which then overwrites that.

The split_pattern.split(...) call is supposed to gate this on "are there explicit servernames", but for an empty servernames it does not gate anything — re.split on an empty string returns [''], which is truthy:

>>> import re
>>> re.compile(r'[ \t\r\n;,]+').split("")
['']
>>> bool([''])
True

So the block is entered for every domain, including those with no servernames, and since my domain isn't Reality it falls into else: allow_insecure = True. The net effect is that the allow_insecure = not domain_db.need_valid_ssl line is effectively dead code for any non-Reality TLS domain — it is always overwritten with True. That True is then written verbatim into the xray JSON here:

https://github.com/hiddify/HiddifyPanel/blob/v12.3.3/hiddifypanel/hutils/proxy/xrayjson.py#L243

'allowInsecure': tls_info['allow_insecure'],

(need_valid_ssl for reference: https://github.com/hiddify/HiddifyPanel/blob/v12.3.3/hiddifypanel/models/domain.py#L131-L133)

What I did on my own server (worked for me, but probably not the complete fix)

As a local workaround I changed that one line so the override block only runs when there are actually non-empty servernames:

# before
if all_snis := split_pattern.split((domain_db.servernames or "").strip()):
# after
if all_snis := [s for s in split_pattern.split((domain_db.servernames or "").strip()) if s]:

After restarting the panel, my direct domain now produces "allowInsecure": false, the valid Let's Encrypt cert verifies normally, and Happ Plus connects again (and it's actually more secure now, since it's doing real cert verification instead of skipping it).

I want to be clear that I do not think this one line is necessarily the proper fix for everyone, and I'm intentionally not opening a PR — I'd rather leave the right design to the maintainers. The reason: need_valid_ssl only reflects the domain mode, not whether a CA-valid cert actually exists. For setups that genuinely have no CA-valid cert (IP-only / self-signed / fake mode / failed ACME), simply dropping allowInsecure isn't enough — those need certificate verification skipped, and since Xray removed allowInsecure, the forward-compatible replacement is what Xray itself suggests: pinnedPeerCertSha256 (pin the server cert by SHA-256) and/or verifyPeerCertByName. The panel already knows the server certificate, so it could compute and emit pinnedPeerCertSha256 automatically for exactly those cases. See the related Xray discussion: XTLS/Xray-core#5655

So in short:

  • domains with a valid CA cert (the common/recommended setup): just stop emitting allowInsecure — normal verification works;
  • domains without a CA-valid cert: migrate to pinnedPeerCertSha256 / verifyPeerCertByName instead of allowInsecure.

My one-line change only covers the first case (but it's safe for the second too — those are already broken by the Xray change regardless).

Steps to reproduce

  1. Have a direct (or cdn/relay) domain with a valid certificate, core_type = xray.
  2. Open the full xray JSON subscription (/<path>/<uuid>/xray/). Every TLS outbound contains "allowInsecure": true.
  3. Import/refresh that subscription in any client bundling Xray-core v26.1.18+ (e.g. Happ Plus) on or after 2026-06-01.
  4. The client refuses the config with: The feature "allowInsecure" has been removed and migrated to "pinnedPeerCertSha256".

Environment

  • OS: Ubuntu 22.04
  • Hiddify Manager (config) version: 12.3.3
  • Hiddify Panel version: 12.3.3
  • Installation type: standard release installer
  • core_type: xray
  • Domain mode: direct, with a valid Let's Encrypt certificate
  • Client: Happ Plus 4.10.2 (bundles Xray-core v26.1.x); reproducible on any Xray-core v26.1.18+ client
  • Note: the same buggy logic is present on current main/dev of HiddifyPanel, not only on the 12.3.3 tag.

Expected behavior

For a domain that has a valid CA certificate, the generated xray config should not contain "allowInsecure": true (or should set it to false / omit it), so that modern Xray-core accepts the config and verifies the certificate normally.

For domains that genuinely cannot be CA-verified (self-signed / IP / fake), the config should use Xray's supported replacement (pinnedPeerCertSha256 / verifyPeerCertByName) instead of the removed allowInsecure flag.

Actual behavior

Every non-Reality TLS outbound in the xray subscription contains "allowInsecure": true, regardless of whether the domain has a valid certificate. Xray-core v26.1.18+ rejects such configs entirely after 2026-06-01, so clients like Happ Plus can no longer connect.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions