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
- Have a
direct (or cdn/relay) domain with a valid certificate, core_type = xray.
- Open the full xray JSON subscription (
/<path>/<uuid>/xray/). Every TLS outbound contains "allowInsecure": true.
- Import/refresh that subscription in any client bundling Xray-core v26.1.18+ (e.g. Happ Plus) on or after 2026-06-01.
- 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.
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:
This is not a bug in Happ. The message comes straight from Xray-core. Newer Xray-core (v26.1.18+) no longer accepts the
allowInsecureTLS option, and there is a hard date switch on it: before2026-06-01it only logged a warning, after that date it became a fatal config error. You can see it in the core itself, inTLSConfig.Build():https://github.com/XTLS/Xray-core/blob/main/infra/conf/transport_internet.go
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": trueinto every non-Reality TLS outbound of the generated xray subscription, even when the domain has a valid, publicly-trusted certificate whereallowInsecureis not needed at all. In my case the domain is a normaldirectdomain with a valid Let's Encrypt certificate, the outbound connects to that same hostname, andserverNameis 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/devtoo and the code is identical there). As far as I can tell the value originates insni_host_server_extractor():https://github.com/hiddify/HiddifyPanel/blob/v12.3.3/hiddifypanel/hutils/proxy/shared.py#L324-L333
The first line computes the right value: for modes that are supposed to have a valid cert (
direct,cdn,relay, etc., perneed_valid_sslinmodels/domain.py) it setsallow_insecure = False. The problem is theif 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 emptyservernamesit does not gate anything —re.spliton an empty string returns[''], which is truthy: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 theallow_insecure = not domain_db.need_valid_sslline is effectively dead code for any non-Reality TLS domain — it is always overwritten withTrue. ThatTrueis then written verbatim into the xray JSON here:https://github.com/hiddify/HiddifyPanel/blob/v12.3.3/hiddifypanel/hutils/proxy/xrayjson.py#L243
(
need_valid_sslfor 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:
After restarting the panel, my
directdomain 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_sslonly 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 /fakemode / failed ACME), simply droppingallowInsecureisn't enough — those need certificate verification skipped, and since Xray removedallowInsecure, the forward-compatible replacement is what Xray itself suggests:pinnedPeerCertSha256(pin the server cert by SHA-256) and/orverifyPeerCertByName. The panel already knows the server certificate, so it could compute and emitpinnedPeerCertSha256automatically for exactly those cases. See the related Xray discussion: XTLS/Xray-core#5655So in short:
allowInsecure— normal verification works;pinnedPeerCertSha256/verifyPeerCertByNameinstead ofallowInsecure.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
direct(orcdn/relay) domain with a valid certificate,core_type = xray./<path>/<uuid>/xray/). Every TLS outbound contains"allowInsecure": true.The feature "allowInsecure" has been removed and migrated to "pinnedPeerCertSha256".Environment
core_type: xraydirect, with a valid Let's Encrypt certificatemain/devof 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 tofalse/ 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 removedallowInsecureflag.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.