Skip to content

fix: add authentication to local mixed inbound to prevent SOCKS5 localhost bypass - #147

Open
godfantom1111-debug wants to merge 1 commit into
hiddify:mainfrom
godfantom1111-debug:fix/socks5-mixed-inbound-auth
Open

fix: add authentication to local mixed inbound to prevent SOCKS5 localhost bypass#147
godfantom1111-debug wants to merge 1 commit into
hiddify:mainfrom
godfantom1111-debug:fix/socks5-mixed-inbound-auth

Conversation

@godfantom1111-debug

Copy link
Copy Markdown

Summary

Fixes the "localhost attack" vulnerability described in https://habr.com/ru/articles/1020080/ and demonstrated by https://github.com/runetfreedom/per-app-split-bypass-poc

The local mixed proxy (127.0.0.1:12334) was running without authentication, allowing any app on the device to connect to it directly and discover the real VPN server IP — bypassing VpnService, per-app split tunneling, and Android Private Space isolation entirely.

Root cause

builder.go:setInbound() creates a TypeMixed inbound with HTTPMixedInboundOptions but leaves Users empty. The hiddify-sing-box fork already supports Users []auth.User on the mixed inbound — it just wasn't being set.

Fix

  • Generate ephemeral random credentials via crypto/rand on each startup (never hardcoded, never persisted to config files)
  • Set them on HTTPMixedInboundOptions.Users
  • Thread credentials through to all internal consumers so existing functionality is not broken:
    • Android tunnel service (admin_tun_service.go): now reads credentials from TypeMixed inbound in addition to TypeSOCKS
    • Profile downloads (url_request.go): Request struct now accepts SocksUser/SocksPass
    • Independent instances (independent_instance.go): credentials stored and used in ContentFromURL

UDP concern

Not an issue here: the mixed inbound listener uses Network: []string{N.NetworkTCP} only — UDP is tunneled over TCP and is therefore protected by the same authentication.

Verification

Tested with per-app-split-bypass-poc on a real Android device (Redmi, Android 16, Life operator, Belarus):

  • Before patch: PoC shows IP via proxy: <VPN server IP>
  • After patch: PoC shows Status: VPN not found / IP via proxy: -

Files changed

File Change
v2/config/hiddify_option.go Add MixedUser/MixedPassword to InboundOptions (runtime only, json:"-")
v2/config/builder.go Generate credentials with crypto/rand, set Users on mixed inbound
extension/system/admin_service_vpn/admin_tun_service.go Handle TypeMixed alongside TypeSOCKS for Android VPN tunnel
v2/hcommon/request/url_request.go Add SocksUser/SocksPass fields to Request
v2/hcore/independent_instance.go Pass credentials into HiddifyInstance, use in ContentFromURL
v2/hcore/static_data.go Add ListenUser/ListenPassword to HiddifyInstance
v2/hcore/start.go Populate ListenUser/ListenPassword from mixed inbound options

The author of the original vulnerability report explicitly asked the community to submit PRs: «Если мы все вместе обратимся к ним или кто-то пришлёт PR, то это исправят»

The local mixed proxy (127.0.0.1:12334) was running without
authentication, allowing any app on the device to connect and
discover the real VPN server IP — bypassing per-app split tunneling
and VpnService isolation entirely, including Android Private Spaces.

Fix: generate ephemeral random credentials (crypto/rand) on each
startup and set them on the HTTPMixedInboundOptions.Users field,
which hiddify-sing-box already supports. The credentials are threaded
through to all internal consumers (tunnel service, profile downloads,
independent instances) so existing functionality is not broken.

Verified with per-app-split-bypass-poc: before the fix the PoC
retrieved the server IP via the unauthenticated proxy; after the fix
it reports "VPN not found" / "IP via proxy: -".

Reported by: https://habr.com/ru/articles/1020080/
PoC: https://github.com/runetfreedom/per-app-split-bypass-poc

Changes:
- v2/config/hiddify_option.go: add MixedUser/MixedPassword fields
- v2/config/builder.go: generate credentials, set Users on inbound
- extension/system/admin_service_vpn/admin_tun_service.go: handle
  TypeMixed in addition to TypeSOCKS for tunnel credential passing
- v2/hcommon/request/url_request.go: add SocksUser/SocksPass to Request
- v2/hcore/independent_instance.go: thread credentials through
- v2/hcore/static_data.go: add ListenUser/ListenPassword fields
- v2/hcore/start.go: populate credentials from mixed inbound
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant