{"record":{"id":"3ffad1fa8be69806","repo":"dotnet/wpf","slug":"sr-format-sr-publishlicensestreamheadertoolong-headerlen","errorCode":null,"errorMessage":"SR.Format(SR.PublishLicenseStreamHeaderTooLong, headerLen, MaxPublishLicenseHeaderLen)","messagePattern":"SR\\.Format\\(SR\\.PublishLicenseStreamHeaderTooLong, headerLen, MaxPublishLicenseHeaderLen\\)","errorType":"exception","errorClass":"FileFormatException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptionTransform.cs","lineNumber":130,"sourceCode":"            // TODO: Use leaveOpen ctor\n            BinaryReader utf8Reader = new BinaryReader(_publishLicenseStream, Encoding.UTF8);\n\n            //\n            // There follows a variable-length header (not to be confused with the physical\n            // stream header). This header allows future expansion, in case we want to store\n            // something in addition to the publish license in the primary instance data stream\n            // for this transform. The first field in the header is the header length in bytes\n            // (including the headerLen field itself).\n            //\n            Int32 headerLen = utf8Reader.ReadInt32();\n            if (headerLen < CU.Int32Size)\n            {\n                throw new FileFormatException(SR.PublishLicenseStreamCorrupt);\n            }\n\n            if (headerLen > MaxPublishLicenseHeaderLen)\n            {\n                throw new FileFormatException(\n                                SR.Format(SR.PublishLicenseStreamHeaderTooLong,\n                                headerLen,\n                                MaxPublishLicenseHeaderLen\n                                ));\n            }\n\n            //\n            // Save any additional bytes in the header that we don't recognize, so we can\n            // write them back out later if necessary. We've already read the headerLen field,\n            // so subtract the size of that field from the amount we have to save.\n            //\n            // No need to use checked{} here since we already made sure that header length is greater than Int32Size\n            Int32 numPublishLicenseHeaderExtraBytes = headerLen - CU.Int32Size;\n            if (numPublishLicenseHeaderExtraBytes > 0)\n            {\n                _publishLicenseHeaderExtraBytes = new byte [numPublishLicenseHeaderExtraBytes];\n                if (PackagingUtilities.ReliableRead(_publishLicenseStream, _publishLicenseHeaderExtraBytes, 0, numPublishLicenseHeaderExtraBytes)\n                        != numPublishLicenseHeaderExtraBytes)","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptionTransform.cs#L112-L148","documentation":"LoadPublishLicense enforces a maximum publish-license header size (MaxPublishLicenseHeaderLen). If the header length Int32 read from the instance data stream exceeds that bound, the header is considered implausible/malicious or from an incompatible future format, and FileFormatException(SR.Format(SR.PublishLicenseStreamHeaderTooLong, headerLen, MaxPublishLicenseHeaderLen)) is thrown with the offending and maximum lengths.","triggerScenarios":"Reading a rights-managed document whose instance data stream starts with an Int32 header length greater than MaxPublishLicenseHeaderLen — produced by a newer format version, by corruption of the length field, or by a deliberately crafted file.","commonSituations":"Opening a document created by a future/newer WPF RM writer with extended headers; a corrupted length field (e.g. pointer bytes read as Int32); fuzzed or malicious files that set an enormous length value; mixing files between incompatible RM implementations.","solutions":["Open the document with a library/runtime version at least as new as the one that wrote it, so longer headers are understood.","Inspect the first Int32 of the RM instance data stream to confirm the header length; if implausibly large, the file is corrupt — restore from backup.","Re-publish the document from the source application with a compatible RM stack to regenerate a standard header.","Catch FileFormatException and report the header-too-long condition (the message includes actual vs max length) to diagnostics.","Do not attempt to patch the length field manually; regenerate the protected document instead."],"exampleFix":"// before: no length sanity check on untrusted data\nint headerLen = binaryReader.ReadInt32();\nReadBytes(binaryReader, headerLen);\n\n// after: bound-check before allocating/reading\nint headerLen = binaryReader.ReadInt32();\nif (headerLen > MaxPublishLicenseHeaderLen)\n{\n    throw new InvalidDataException(\n        $\"Publish license header too long: {headerLen} > {MaxPublishLicenseHeaderLen}. \" +\n        \"File may be from a newer format or corrupt.\");\n}","handlingStrategy":"validation","validationCode":"// sanity-check the declared header length against a sane maximum\nstream.Seek(0, SeekOrigin.Begin);\nSpan<byte> buf = stackalloc byte[4];\nint headerLen = stream.Read(buf) == 4 ? BitConverter.ToInt32(buf) : 0;\nif (headerLen > MaxPublishLicenseHeaderLen)\n    throw new InvalidDataException($\"Header length {headerLen} exceeds max {MaxPublishLicenseHeaderLen}; file from newer format or corrupt.\");","typeGuard":"static bool HeaderLengthInBounds(Stream s, int maxLen)\n{\n    long pos = s.Position;\n    Span<byte> b = stackalloc byte[4];\n    int v = s.Read(b) == 4 ? BitConverter.ToInt32(b) : int.MaxValue;\n    s.Seek(pos, SeekOrigin.Begin);\n    return v >= sizeof(int) && v <= maxLen;\n}","tryCatchPattern":"try\n{\n    publishLicense = transform.LoadPublishLicense();\n}\ncatch (FileFormatException ex) when (ex.Message.Contains(\"too long\"))\n{\n    log.Warn(\"Publish license header exceeds supported length; try a newer runtime or re-publish the document.\", ex);\n    throw;\n}","preventionTips":["Open protected documents with a runtime at least as new as the writer.","Reject implausibly large length fields early when parsing untrusted streams.","Never allocate buffers directly from untrusted length prefixes without bounds checks.","Keep the RM/WPF stack updated to support newer header extensions."],"tags":["wpf","packaging","rights-management","file-format","bounds-check"],"backgroundTag":"value-out-of-range","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}