icsharpcode/ILSpy · error · InvalidDataException

Invalid BAML signature length.

Error message

Invalid BAML signature length.

What it means

Thrown by BamlReader.ReadSignature after reading the 4-byte length prefix of the BAML signature. The check len >> 1 != MSBAML_SIG.Length guards against a crafted length value before any allocation, because the only accepted signature is the fixed 6-char 'MSBAML'. A mismatch means the stream is not valid BAML or has been tampered with.

Source

Thrown at ICSharpCode.BamlDecompiler/Baml/BamlReader.cs:71

					return false;
				var sig = new string(rdr.ReadChars(len));
				return sig == MSBAML_SIG;
			}
			finally
			{
				str.Position = pos;
			}
		}

		static string ReadSignature(Stream str)
		{
			var rdr = new BinaryReader(str, Encoding.Unicode);
			uint len = rdr.ReadUInt32();
			// len is read straight from the file, before the MSBAML_SIG check below. The only
			// accepted signature is the fixed-length "MSBAML", so reject any other length here
			// rather than allocating an attacker-sized string from a crafted value.
			if (len >> 1 != (uint)MSBAML_SIG.Length)
				throw new InvalidDataException("Invalid BAML signature length.");
			var sig = new string(rdr.ReadChars((int)(len >> 1)));
			rdr.ReadBytes((int)(((len + 3) & ~3) - len));
			return sig;
		}

		public static BamlDocument ReadDocument(Stream str, CancellationToken token)
		{
			var ret = new BamlDocument();
			var reader = new BamlBinaryReader(str);
			ret.Signature = ReadSignature(str);
			if (ret.Signature != MSBAML_SIG)
				throw new NotSupportedException();
			ret.ReaderVersion = new BamlDocument.BamlVersion { Major = reader.ReadUInt16(), Minor = reader.ReadUInt16() };
			ret.UpdaterVersion = new BamlDocument.BamlVersion { Major = reader.ReadUInt16(), Minor = reader.ReadUInt16() };
			ret.WriterVersion = new BamlDocument.BamlVersion { Major = reader.ReadUInt16(), Minor = reader.ReadUInt16() };
			if (ret.ReaderVersion.Major != 0 || ret.ReaderVersion.Minor != 0x60 ||
				ret.UpdaterVersion.Major != 0 || ret.UpdaterVersion.Minor != 0x60 ||
				ret.WriterVersion.Major != 0 || ret.WriterVersion.Minor != 0x60)

View on GitHub (pinned to 60c08fcb74)

Solutions

  1. Make sure you are feeding the actual BAML resource stream (e.g. the entry from a .g.resources stream), not the whole assembly.
  2. Probe the stream first with BamlReader.IsBamlHeader, which performs the same length/signature check non-destructively.
  3. If the resource is corrupt, re-obtain it from the original assembly.

Example fix

// before
using var fs = File.OpenRead(path);
var doc = BamlReader.ReadDocument(fs, ct); // throws if `path` is not a BAML stream

// after
using var fs = File.OpenRead(path);
if (!BamlReader.IsBamlHeader(fs))
    throw new InvalidDataException("Selected stream is not MSBAML.");
fs.Position = 0;
var doc = BamlReader.ReadDocument(fs, ct);
Defensive patterns

Strategy: validation

Validate before calling

// call before ReadDocument
public static bool IsLikelyBaml(Stream str)
{
    return BamlReader.IsBamlHeader(str); // restores position itself
}

Try / catch

try {
    var doc = BamlReader.ReadDocument(stream, token);
} catch (InvalidDataException ex) when (ex.Message.Contains("signature length")) {
    // not a BAML stream; pick the correct resource instead
}

Prevention

When it happens

Trigger: ReadDocument is given a stream whose first uint (the signature length, stored as char-count<<1) is not exactly 12 (i.e. 6 chars). Typical when the stream is a plain PE/assembly, a managed resource that is not BAML, or arbitrary bytes.

Common situations: Pointing the BAML decompiler at a whole .NET DLL instead of the embedded BAML resource; selecting a non-BAML resource entry; corrupted/garbled BAML; an attacker-crafted stream with a huge length value.

Related errors


AI-assisted analysis of icsharpcode/ILSpy@60c08fcb74 (2026-08-13). Data as JSON: /api/errors/507f620f27434a54. Report an issue: GitHub.