{"record":{"id":"3699ed2eb698ff82","repo":"shadow1ng/fscan","slug":"node-rdp-protocol-pdu-sec-bad-license-header","errorCode":"NODE_RDP_PROTOCOL_PDU_SEC_BAD_LICENSE_HEADER","errorMessage":"NODE_RDP_PROTOCOL_PDU_SEC_BAD_LICENSE_HEADER","messagePattern":"NODE_RDP_PROTOCOL_PDU_SEC_BAD_LICENSE_HEADER","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/grdp/protocol/sec/sec.go","lineNumber":730,"sourceCode":"\tc.sendFlagged(EXCHANGE_PKT, message.serialize())\n\treturn true\n}\nfunc (c *Client) sendInfoPkt() {\n\tvar secFlag uint16 = INFO_PKT\n\tif c.enableEncryption {\n\t\tsecFlag |= ENCRYPT\n\t}\n\n\tglog.Debug(\"RdpVersion:\", c.ClientCoreData().RdpVersion, \":\", gcc.RDP_VERSION_5_PLUS)\n\tc.sendFlagged(secFlag, c.info.Serialize(c.ClientCoreData().RdpVersion == gcc.RDP_VERSION_5_PLUS))\n}\n\nfunc (c *Client) recvLicenceInfo(channel string, s []byte) {\n\tglog.Debug(\"sec recvLicenceInfo\", hex.EncodeToString(s))\n\tr := bytes.NewReader(s)\n\th := readSecurityHeader(r)\n\tif (h.securityFlag & LICENSE_PKT) == 0 {\n\t\tc.Emit(\"error\", errors.New(\"NODE_RDP_PROTOCOL_PDU_SEC_BAD_LICENSE_HEADER\"))\n\t\treturn\n\t}\n\n\tp := lic.ReadLicensePacket(r)\n\tswitch p.BMsgtype {\n\tcase lic.NEW_LICENSE:\n\t\tglog.Info(\"sec NEW_LICENSE\")\n\t\tc.Emit(\"success\")\n\t\tgoto connect\n\tcase lic.ERROR_ALERT:\n\t\tmessage := p.LicensingMessage.(*lic.ErrorMessage)\n\t\tglog.Info(\"sec ERROR_ALERT and ErrorCode:\", message.DwErrorCode)\n\t\tif message.DwErrorCode == lic.STATUS_VALID_CLIENT && message.DwStateTransaction == lic.ST_NO_TRANSITION {\n\t\t\tgoto connect\n\t\t}\n\t\tgoto retry\n\tcase lic.LICENSE_REQUEST:\n\t\tglog.Info(\"sec LICENSE_REQUEST\")","sourceCodeStart":712,"sourceCodeEnd":748,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/libs/grdp/protocol/sec/sec.go#L712-L748","documentation":"recvLicenceInfo in sec/sec.go reads the security header of an incoming license PDU on the channel. If the securityFlag does not include LICENSE_PKT (0x0080), the data is not a valid license packet, so the client emits the node-rdp-style constant error NODE_RDP_PROTOCOL_PDU_SEC_BAD_LICENSE_HEADER and stops processing.","triggerScenarios":"Server sends a licensing-phase message whose security header flags lack the LICENSE_PKT bit — e.g. a differently framed PDU delivered on the licensing path, stream misalignment making readSecurityHeader read the wrong bytes, or a server that doesn't do licensing but still sends data where a license packet is expected.","commonSituations":"Connecting to servers with nonstandard or disabled licensing (e.g. some Linux RDP servers, xrdp misconfigurations); connecting when license negotiation state is out of order after a reconnect; a preceding parse bug shifting bytes so flags read incorrectly.","solutions":["Log the raw header bytes (h.securityFlag, h.securitySequence) to confirm misalignment vs. a genuinely non-license packet.","Verify earlier PDU framing: ensure the length consumed by the previous packet matches, so readSecurityHeader starts at the true header offset.","If the server doesn't implement licensing properly, configure it to skip the license phase (e.g. fix xrdp/terminal server licensing settings) or patch the client to ignore non-license data on this channel.","Update grdp/node-rdp-derived code so recvLicenceInfo tolerates and skips unexpected PDUs instead of erroring."],"exampleFix":"// before\nif (h.securityFlag & LICENSE_PKT) == 0 {\n    c.Emit(\"error\", errors.New(\"NODE_RDP_PROTOCOL_PDU_SEC_BAD_LICENSE_HEADER\"))\n    return\n}\n// after\nif (h.securityFlag & LICENSE_PKT) == 0 {\n    glog.Warnf(\"skipping non-license packet on licence channel, flags=0x%x\", h.securityFlag)\n    return\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isLicensePacket(h securityHeader) bool {\n    return (h.securityFlag & LICENSE_PKT) != 0\n}","tryCatchPattern":"client.On(\"error\", func(err error) {\n    if strings.Contains(err.Error(), \"BAD_LICENSE_HEADER\") {\n        glog.Warn(\"non-license data on licence channel; ignoring\")\n        return\n    }\n    glog.Error(\"rdp error: \", err)\n})","preventionTips":["Confirm the server implements RDP licensing (or is configured to skip it, e.g. xrdp settings)","Check PDU framing upstream — a misaligned stream corrupts the security header flags","Log h.securityFlag values to distinguish real non-license packets from desync"],"tags":["rdp","licensing","protocol","security-header"],"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"}