{"record":{"id":"a92095c3f1c89c4f","repo":"shadow1ng/fscan","slug":"node-rdp-protocol-t125-mcs-server-must-confirm-sta","errorCode":null,"errorMessage":"NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL","messagePattern":"NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/grdp/protocol/t125/mcs.go","lineNumber":512,"sourceCode":"\t}\n\n\tif !readMCSPDUHeader(option, CHANNEL_JOIN_CONFIRM) {\n\t\tc.Emit(\"error\", errors.New(\"NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM\"))\n\t\treturn\n\t}\n\n\tconfirm, _ := per.ReadEnumerates(r)\n\tuserId, _ := per.ReadInteger16(r)\n\tuserId += MCS_USERCHANNEL_BASE\n\n\tif c.userId != userId {\n\t\tc.Emit(\"error\", errors.New(\"NODE_RDP_PROTOCOL_T125_MCS_INVALID_USER_ID\"))\n\t\treturn\n\t}\n\n\tchannelId, _ := per.ReadInteger16(r)\n\tif (confirm != 0) && (channelId == uint16(MCS_GLOBAL_CHANNEL_ID) || channelId == c.userId) {\n\t\tc.Emit(\"error\", errors.New(\"NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL\"))\n\t\treturn\n\t}\n\tglog.Debug(\"Confirm channelId:\", channelId)\n\tif confirm == 0 && c.serverNetworkData != nil {\n\t\tfor i := 0; i < int(c.serverNetworkData.ChannelCount); i++ {\n\t\t\tif channelId == c.serverNetworkData.ChannelIdArray[i] {\n\t\t\t\tvar t MCSChannelInfo\n\t\t\t\tt.ID = channelId\n\t\t\t\tt.Name = string(c.clientNetworkData.ChannelDefArray[i].Name[:])\n\t\t\t\tc.channels = append(c.channels, t)\n\t\t\t}\n\t\t}\n\t}\n\tc.channelsConnected++\n\tc.connectChannels()\n}\n\nfunc (c *MCSClient) Pack(data []byte, channelId uint16) []byte {","sourceCodeStart":494,"sourceCodeEnd":530,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/libs/grdp/protocol/t125/mcs.go#L494-L530","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"c.On(\"error\", func(err error) {\n    if strings.Contains(err.Error(), \"SERVER_MUST_CONFIRM_STATIC_CHANNEL\") {\n        log.Println(\"server refused static channel join; target is nonconformant or proxied\")\n    }\n})","preventionTips":["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"],"tags":["rdp","mcs","protocol-violation","channel-join"],"backgroundTag":"operation-not-supported","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}