MHSanaei/3x-ui · critical

xray binary exceeds %d bytes

Error message

xray binary exceeds %d bytes

What it means

Returned during UpdateXray's extraction step when a file expanded from the downloaded zip streams more than maxXrayBinaryBytes (200 MiB) into the temp file. This is the zip-bomb guard: the archive passed the outer size and SHA-256 checks, but a single decompressed entry exceeding 200 MiB means the zip is malicious or malformed. The real xray binary is ~20-30 MiB, so the guard should never trip on a legitimate release.

Source

Thrown at internal/web/service/server.go:1050

		}
		tmpFile, err := os.CreateTemp(filepath.Dir(fileName), ".xray-*")
		if err != nil {
			return err
		}
		tmpPath := tmpFile.Name()
		ok := false
		defer func() {
			_ = tmpFile.Close()
			if !ok {
				_ = os.Remove(tmpPath)
			}
		}()
		n, err := io.Copy(tmpFile, io.LimitReader(zipFile, maxXrayBinaryBytes+1))
		if err != nil {
			return err
		}
		if n > maxXrayBinaryBytes {
			return fmt.Errorf("xray binary exceeds %d bytes", maxXrayBinaryBytes)
		}
		if err := tmpFile.Chmod(0o755); err != nil {
			return err
		}
		if err := tmpFile.Close(); err != nil {
			return err
		}
		if runtime.GOOS == "windows" {
			_ = os.Remove(fileName)
		}
		if err := os.Rename(tmpPath, fileName); err != nil {
			return err
		}
		ok = true
		return nil
	}

	// 4. Extract correct binary

View on GitHub (pinned to ad32144c42)

Solutions

  1. Retry the update; if it persists, treat the host's download path as untrusted and verify manually
  2. Download the zip by hand, run sha256sum against the official .dgst, and unzip -l to inspect entry sizes
  3. Only consider raising maxXrayBinaryBytes if official binaries ever approach 200 MiB
Defensive patterns

Strategy: validation

Validate before calling

for _, f := range zipReader.File {
    if f.UncompressedSize64 > maxXrayBinaryBytes {
        return fmt.Errorf("zip entry %s expands to %d bytes; refusing", f.Name, f.UncompressedSize64)
    }
}

Prevention

When it happens

Trigger: A crafted zip whose entries decompress far beyond the archive size; a corrupted zip whose entry headers claim/expand bogus sizes; extraction reading the wrong entry because the zip layout changed.

Common situations: Effectively only with tampered/corrupted archives that also passed the checksum (impossible unless the .dgst itself was compromised) — or after a genuine xray binary exceeds 200 MiB, which has never happened.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/96c262afe1296410. Report an issue: GitHub.