projectdiscovery/nuclei · error

could not hex decode binary: %s

Error message

could not hex decode binary: %s

What it means

Template compilation error from Matcher.CompileMatchers (pkg/operators/matchers/compile.go:62). For `type: binary` matchers, every `binary:` entry is hex-decoded with hex.DecodeString at compile time; invalid hex (odd length or non-hex characters) returns this error including the offending value. Unlike word matchers' optional 'hex' encoding, binary matchers are strict.

Source

Thrown at pkg/operators/matchers/compile.go:62

	// Compile the regexes (with shared cache)
	for _, regex := range matcher.Regex {
		if cached, err := cache.Regex().GetIFPresent(regex); err == nil && cached != nil {
			matcher.regexCompiled = append(matcher.regexCompiled, cached)
			continue
		}
		compiled, err := regexp.Compile(regex)
		if err != nil {
			return fmt.Errorf("could not compile regex: %s", regex)
		}
		_ = cache.Regex().Set(regex, compiled)
		matcher.regexCompiled = append(matcher.regexCompiled, compiled)
	}

	// Compile and validate binary Values in matcher
	for _, value := range matcher.Binary {
		if decoded, err := hex.DecodeString(value); err != nil {
			return fmt.Errorf("could not hex decode binary: %s", value)
		} else {
			matcher.binaryDecoded = append(matcher.binaryDecoded, string(decoded))
		}
	}

	// Compile the dsl expressions (with shared cache)
	for _, dslExpression := range matcher.DSL {
		if cached, err := cache.DSL().GetIFPresent(dslExpression); err == nil && cached != nil {
			matcher.dslCompiled = append(matcher.dslCompiled, cached)
			continue
		}
		compiledExpression, err := govaluate.NewEvaluableExpressionWithFunctions(dslExpression, dsl.HelperFunctions)
		if err != nil {
			return &dsl.CompilationError{DslSignature: dslExpression, WrappedError: err}
		}
		_ = cache.DSL().Set(dslExpression, compiledExpression)
		matcher.dslCompiled = append(matcher.dslCompiled, compiledExpression)
	}

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Ensure each binary value is an even-length pure hex string: strip spaces/colons/0x, then verify length % 2 == 0
  2. Verify with a quick shell check: `echo -n '4d5a...' | xxd -r -p | xxd` round-trips
  3. If the intent is to match literal text, use a word matcher instead of binary
  4. Validate the template with `nuclei -validate -t template.yaml`

Example fix

# before
binary:
  - '0x4d5a'
# after
binary:
  - '4d5a'
Defensive patterns

Strategy: validation

Validate before calling

for _, b := range m.Binary {
	if len(b)%2 != 0 { return fmt.Errorf("odd-length hex %q", b) }
	for _, c := range b {
		if !strings.ContainsRune("0123456789abcdefABCDEF", c) {
				return fmt.Errorf("non-hex char %q in %q", c, b)
			}
	}
}

Type guard

func isPureHex(s string) bool {
	if len(s)%2 != 0 { return false }
	_, err := hex.DecodeString(s)
	return err == nil
}

Try / catch

if err := m.CompileMatchers(); err != nil && strings.Contains(err.Error(), "could not hex decode binary") {
	// strip 0x/spaces from the reported value and re-validate
}

Prevention

When it happens

Trigger: A binary matcher value with an odd number of hex digits ('4d5'), a '0x' prefix ('0x4d5a'), embedded whitespace, or a raw string pasted where hex was expected.

Common situations: Converting packet signatures/PoC byte sequences to templates and dropping a nibble; pasting 'MZ' style hex with separators (e.g. '4d 5a') or 0x prefixes from Wireshark/ghidra output.

Related errors


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/4938f811f43972e0. Report an issue: GitHub.