JuliusBrussee/caveman · critical

production refuses low-diversity %s

Error message

production refuses low-diversity %s

What it means

Produced by validateProductionTextSecrets (env.go:107): the secret is at least 32 characters long but fewer than 8 distinct byte values appear in it (distinctBytes counts unique bytes). This catches long but low-entropy secrets such as repeated characters or simple patterns, which length alone would let through. The variable name is included.

Source

Thrown at shared/platform/env/env.go:107

	if Bool("CAVE_REPLAY_ENABLED", false) {
		if err := validateProductionTextSecrets([]string{"CAVE_ROUTER_REPLAY_TOKEN"}); err != nil {
			return err
		}
	}
	return validateProductionPublicURL()
}

func validateProductionTextSecrets(names []string) error {
	for _, name := range names {
		v := strings.TrimSpace(os.Getenv(name))
		if v == "" || v == "generated" || strings.Contains(strings.ToLower(v), "changeme") {
			return fmt.Errorf("production refuses default or empty %s", name)
		}
		if len(v) < 32 {
			return fmt.Errorf("production requires %s to contain at least 32 characters", name)
		}
		if distinctBytes([]byte(v)) < 8 {
			return fmt.Errorf("production refuses low-diversity %s", name)
		}
	}
	return nil
}

func validateProductionPublicURL() error {
	publicURL := strings.TrimSpace(os.Getenv("CAVE_PUBLIC_URL"))
	u, err := url.Parse(publicURL)
	if err != nil || u.Scheme != "https" || u.Hostname() == "" || u.User != nil || u.RawQuery != "" || u.Fragment != "" || (u.Path != "" && u.Path != "/") {
		return fmt.Errorf("production requires CAVE_PUBLIC_URL to be an HTTPS origin without credentials, path, query, or fragment")
	}
	return nil
}

func distinctBytes(value []byte) int {
	seen := map[byte]struct{}{}
	for _, b := range value {
		seen[b] = struct{}{}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Generate the secret from a CSPRNG: openssl rand -base64 48 gives high byte diversity by construction.
  2. If humans must type it, use a passphrase from many distinct words/characters rather than repetition.
  3. Verify programmatically before deploy: count distinct bytes and require >=8 (see validation snippet).
  4. Update the secret store and restart so the gate re-evaluates the new value.

Example fix

# before
CAVE_BOOTSTRAP_TOKEN=00000000000000000000000000000000

# after
CAVE_BOOTSTRAP_TOKEN=$(openssl rand -base64 48)
Defensive patterns

Strategy: validation

Validate before calling

func diverse(v string) bool {
    seen := map[byte]struct{}{}
    for i := range v { seen[v[i]] = struct{}{} }
    return len(seen) >= 8
}

Try / catch

if err := env.RefuseProductionDefaults(); err != nil {
    return err // replace repeated-pattern secrets with CSPRNG output
}

Prevention

When it happens

Trigger: CAVE_ENV is production and a checked secret of >=32 chars contains fewer than 8 unique bytes - e.g. 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' (1 distinct byte) or 'abcabcabc...' (3 distinct bytes).

Common situations: Padding a short password with repetition to satisfy a length rule; placeholder padding like 'x'*40 left by a script; keyboard walks ('qwertyqwerty...'); template strings repeated to fill a field.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/04726b9d9e260c48. Report an issue: GitHub.