shadow1ng/fscan · error
NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNE
Error message
NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL
What it means
When the server sends a Channel Join Confirm with confirm != 0 (refused) for a static channel — either the MCS Global Channel or the user's own channel — the library emits this sentinel error. T.125 requires the server to always accept joins for these mandatory static channels; a refusal means a broken or nonstandard server.
Source
Thrown at libs/grdp/protocol/t125/mcs.go:512
}
if !readMCSPDUHeader(option, CHANNEL_JOIN_CONFIRM) {
c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM"))
return
}
confirm, _ := per.ReadEnumerates(r)
userId, _ := per.ReadInteger16(r)
userId += MCS_USERCHANNEL_BASE
if c.userId != userId {
c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_INVALID_USER_ID"))
return
}
channelId, _ := per.ReadInteger16(r)
if (confirm != 0) && (channelId == uint16(MCS_GLOBAL_CHANNEL_ID) || channelId == c.userId) {
c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL"))
return
}
glog.Debug("Confirm channelId:", channelId)
if confirm == 0 && c.serverNetworkData != nil {
for i := 0; i < int(c.serverNetworkData.ChannelCount); i++ {
if channelId == c.serverNetworkData.ChannelIdArray[i] {
var t MCSChannelInfo
t.ID = channelId
t.Name = string(c.clientNetworkData.ChannelDefArray[i].Name[:])
c.channels = append(c.channels, t)
}
}
}
c.channelsConnected++
c.connectChannels()
}
func (c *MCSClient) Pack(data []byte, channelId uint16) []byte {View on GitHub (pinned to 95cc12e753)
Solutions
- Verify the target is a standard RDP server; try connecting with mstsc or freerdp to confirm server behavior.
- Check whether an RDP gateway/proxy sits in the path and relax its channel restrictions.
- Log the refused channelId and confirm code to report/diagnose the server implementation.
- If you control the client, treat refusal of a non-critical static channel as fatal-but-reported instead of aborting the whole session.
Defensive patterns
Strategy: fallback
Try / catch
c.On("error", func(err error) {
if strings.Contains(err.Error(), "SERVER_MUST_CONFIRM_STATIC_CHANNEL") {
log.Println("server refused static channel join; target is nonconformant or proxied")
}
}) Prevention
- Validate target servers with a reference RDP client first
- Document RDP gateway/proxy restrictions in target inventories
- Treat static-channel refusal as a server-conformance signal, not a transient error
When it happens
Trigger: recvChannelJoinConfirm reads channelId and the condition (confirm != 0) && (channelId == MCS_GLOBAL_CHANNEL_ID || channelId == c.userId) is true, i.e. the server explicitly refused the join for a static channel.
Common situations: Connecting through an RDP proxy/gateway or hardened terminal server that restricts channel joins; a non-Windows RDP implementation with incomplete T.125 support; MITM devices mangling the channel id.
Related errors
- NODE_RDP_PROTOCOL_T125_MCS_INVALID_USER_ID
- bad BER tags
- invalid expected BER tag
- NODE_RDP_PROTOCOL_T125_MCS_BAD_HEADER
- NODE_RDP_PROTOCOL_T125_MCS_SERVER_REJECT_USER
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/a92095c3f1c89c4f.
Report an issue: GitHub.