{"record":{"id":"9acacec148f12b0a","repo":"shadow1ng/fscan","slug":"invalid-expected-mcs-opcode-receive-data","errorCode":null,"errorMessage":"Invalid expected MCS opcode receive data","messagePattern":"Invalid expected MCS opcode receive data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/grdp/protocol/t125/mcs.go","lineNumber":454,"sourceCode":"\tc.transport.Write(buff.Bytes())\n}\n\nfunc (c *MCSClient) recvData(s []byte) {\n\tglog.Debug(\"msc on data recvData:\", hex.EncodeToString(s))\n\n\tr := bytes.NewReader(s)\n\toption, err := core.ReadUInt8(r)\n\tif err != nil {\n\t\tc.Emit(\"error\", err)\n\t\treturn\n\t}\n\n\tif readMCSPDUHeader(option, DISCONNECT_PROVIDER_ULTIMATUM) {\n\t\tc.Emit(\"error\", errors.New(\"MCS DISCONNECT_PROVIDER_ULTIMATUM\"))\n\t\tc.transport.Close()\n\t\treturn\n\t} else if !readMCSPDUHeader(option, c.recvOpCode) {\n\t\tc.Emit(\"error\", errors.New(\"Invalid expected MCS opcode receive data\"))\n\t\treturn\n\t}\n\n\tuserId, _ := per.ReadInteger16(r)\n\tuserId += MCS_USERCHANNEL_BASE\n\n\tchannelId, _ := per.ReadInteger16(r)\n\tper.ReadEnumerates(r)\n\tsize, _ := per.ReadLength(r)\n\t// channel ID doesn't match a requested layer\n\tfound := false\n\tchannelName := \"\"\n\tfor _, channel := range c.channels {\n\t\tif channel.ID == channelId {\n\t\t\tfound = true\n\t\t\tchannelName = channel.Name\n\t\t\tbreak\n\t\t}","sourceCodeStart":436,"sourceCodeEnd":472,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/libs/grdp/protocol/t125/mcs.go#L436-L472","documentation":"In recvData, after ruling out DISCONNECT_PROVIDER_ULTIMATUM, the header must match c.recvOpCode (normally SEND_DATA_INDICATION). If readMCSPDUHeader(option, c.recvOpCode) fails, the client received an MCS PDU it did not expect in the data phase and emits this error. It indicates a protocol sequence violation or unhandled PDU type mid-session.","triggerScenarios":"A 'data' event in the established-session phase carries an MCS PDU whose opcode (option>>2) is neither DISCONNECT_PROVIDER_ULTIMATUM nor SEND_DATA_INDICATION — e.g. a CHANNEL_JOIN_CONFIRM arriving late, or a server-to-client PDU type this fork doesn't handle.","commonSituations":"Responses to earlier requests arriving after the client switched to recvData (handler registration race between Once('data', ...) and On('data', recvData)); servers sending proprietary/extension PDUs; framing desynchronization after a partial read.","solutions":["Log the unexpected opcode (option>>2) to identify which PDU type arrived and add a handler or skip logic for it.","Ensure all request/response pairs (channel join etc.) complete before registering recvData as the permanent 'data' handler.","Consider buffering/skipping unknown PDUs instead of erroring out, matching FreeRDP's tolerant behavior.","If desynchronization is suspected, dump the hex stream and verify PDU boundaries against T.125 framing."],"exampleFix":"// before\n} else if !readMCSPDUHeader(option, c.recvOpCode) {\n    c.Emit(\"error\", errors.New(\"Invalid expected MCS opcode receive data\"))\n    return\n}\n// after\n} else if !readMCSPDUHeader(option, c.recvOpCode) {\n    glog.Warn(\"unexpected MCS opcode\", option>>2, \"- skipping\")\n    return\n}","handlingStrategy":"fallback","validationCode":"// Pre-dispatch check of the opcode in the data stream:\nop := (buf[0] >> 2)\nif op != 26 { // SEND_DATA_INDICATION\n    glog.Warn(\"unexpected MCS opcode during data phase:\", op)\n}","typeGuard":null,"tryCatchPattern":"mcs.On(\"error\", func(err error) {\n    if strings.Contains(err.Error(), \"Invalid expected MCS opcode\") {\n        // log opcode, skip or resynchronize instead of hard-failing\n    }\n})","preventionTips":["Finish all Once('data') request/response exchanges before installing recvData as permanent handler.","Log and skip unknown PDU opcodes rather than aborting the session.","Validate PDU framing against T.125 when adding new message types."],"tags":["rdp","mcs","protocol-parsing","unexpected-pdu"],"backgroundTag":"unexpected-response-shape","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"}