caddyserver/caddy · error · APIError

Buggy browser is sending null Origin header.

Error message

Buggy browser is sending null Origin header.

What it means

loadSTEK() returned an error other than fs.ErrNotExist while reading the persisted STEK from storage. The provider distinguishes 'no keys yet' (fine, will create) from any other read failure (a real problem), and this error is the latter.

Source

Thrown at admin.go:849

		return
	}
	if strings.Contains(r.Header.Get("Sec-Fetch-Mode"), "no-cors") {
		// turns out web pages can just disable the same-origin policy (!???!?)
		// but at least browsers let us know that's the case, holy heck
		h.handleError(w, r, APIError{
			HTTPStatus: http.StatusBadRequest,
			Err:        errors.New("client attempted to make request by disabling same-origin policy using no-cors mode"),
			Message:    "Disabling same-origin restrictions is not allowed.",
		})
		return
	}
	if r.Header.Get("Origin") == "null" {
		// bug in Firefox in certain cross-origin situations (yikes?)
		// (not strictly a security vuln on its own, but it's red flaggy,
		// since it seems to manifest in cross-origin contexts)
		h.handleError(w, r, APIError{
			HTTPStatus: http.StatusBadRequest,
			Err:        errors.New("invalid origin 'null'"),
			Message:    "Buggy browser is sending null Origin header.",
		})
		return
	}

	if h.enforceHost {
		// DNS rebinding mitigation
		err := h.checkHost(r)
		if err != nil {
			h.handleError(w, r, err)
			return
		}
	}

	_, hasOriginHeader := r.Header["Origin"]
	_, hasSecHeader := r.Header["Sec-Fetch-Mode"]
	if h.enforceOrigin || hasOriginHeader || hasSecHeader {
		// cross-site mitigation

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Inspect the wrapped error to see if it is a connectivity/permission failure (fix storage) versus a decode failure (corrupt data).
  2. For corrupt local data, stop Caddy and delete the STEK key from the data directory (it lives under the storage root; deleting it forces clean regeneration — only session resumption is lost).
  3. For remote storage, restore backend health and restart Caddy.
  4. Verify all cluster instances run compatible Caddy versions so the gob encoding of distributedSTEK matches.

Example fix

// before: corrupt stek key file in storage
ls /var/lib/caddy/locks  # locate storage keys

# after: stop caddy, remove the stek entry, restart to regenerate
systemctl stop caddy
rm -rf /var/lib/caddy/stek*  # path depends on storage layout
systemctl start caddy
Defensive patterns

Strategy: retry

Type guard

// Distinguish 'no keys yet' (benign) from real load failures when implementing custom storage:
_, err := storage.Load(ctx, stekKeyName)
if errors.Is(err, fs.ErrNotExist) { /* first run: ok */ } else if err != nil { /* real failure */ }

Try / catch

On this error, inspect errors.Is/As on the chain: fs.ErrNotExist is handled internally, so any surfaced error is a genuine storage fault — remediate storage, then restart to retry the load.

Prevention

When it happens

Trigger: storage.Load on the STEK key returns a non-ErrNotExist error: storage backend unreachable, permission denied on the key file, or gob decoding of a corrupt/truncated persisted STEK fails.

Common situations: Corrupted storage after a crash mid-write; partially synced distributed storage (S3 eventual consistency anomalies); permission changes on the data directory; Redis flushing/failing between the lock and the load.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/8f0af6d583885b42. Report an issue: GitHub.