gofiber/fiber · critical

[CSRF] Invalid origin format in configuration:${maskedOrigin

Error message

[CSRF] Invalid origin format in configuration:${maskedOrigin}

What it means

CSRF trusted-origin validation (csrf.go:84-94) mirrors CORS: entries containing "://*." are stripped of the wildcard and passed to normalizeOrigin. A failure (unparseable URL, empty host, embedded '*', userinfo, path, query, fragment) panics at startup so a broken TrustedOrigins list cannot silently accept or reject the wrong origins.

Source

Thrown at middleware/csrf/csrf.go:90

	var sessionManager *sessionManager
	var storageManager *storageManager
	if cfg.Session != nil {
		sessionManager = newSessionManager(cfg.Session)
	} else {
		storageManager = newStorageManager(cfg.Storage, redactKeys)
	}

	// Pre-parse trusted origins
	trustedOrigins := []string{}
	trustedSubOrigins := []subdomain{}

	for _, origin := range cfg.TrustedOrigins {
		trimmedOrigin := utils.TrimSpace(origin)
		if i := strings.Index(trimmedOrigin, "://*."); i != -1 {
			withoutWildcard := trimmedOrigin[:i+len("://")] + trimmedOrigin[i+len("://*."):]
			isValid, normalizedOrigin := normalizeOrigin(withoutWildcard)
			if !isValid {
				panic("[CSRF] Invalid origin format in configuration:" + maskValue(origin))
			}
			schemeSep := strings.Index(normalizedOrigin, "://") + len("://")
			sd := subdomain{prefix: normalizedOrigin[:schemeSep], suffix: normalizedOrigin[schemeSep:]}
			trustedSubOrigins = append(trustedSubOrigins, sd)
		} else {
			isValid, normalizedOrigin := normalizeOrigin(trimmedOrigin)
			if !isValid {
				panic("[CSRF] Invalid origin format in configuration:" + maskValue(origin))
			}
			trustedOrigins = append(trustedOrigins, normalizedOrigin)
		}
	}

	// Create the handler outside of the returned function
	handler := &Handler{
		config:         cfg,
		sessionManager: sessionManager,
		storageManager: storageManager,

View on GitHub (pinned to 9a4c7e57fe)

Solutions

  1. Use the bare wildcard form: TrustedOrigins: []string{"https://*.example.com"}.
  2. Ensure each entry has scheme + non-empty host and no path/query/fragment.
  3. Validate env-derived origin lists with a unit test before passing them to csrf.New.

Example fix

// before
csrf.New(csrf.Config{TrustedOrigins: []string{"https://*.example.com/login"}})

// after
csrf.New(csrf.Config{TrustedOrigins: []string{"https://*.example.com"}})
Defensive patterns

Strategy: validation

Validate before calling

func validateCSRFTrustedWildcardOrigins(origins []string) error {
    for _, o := range origins {
        i := strings.Index(o, "://*.")
        if i == -1 { continue }
        base := o[:i+len("://")] + o[i+len("://*."):]
        u, err := url.Parse(base)
        if err != nil || u.Host == "" || strings.Contains(u.Host, "*") ||
            (u.Path != "" && u.Path != "/") {
            return fmt.Errorf("invalid CSRF wildcard origin %q", o)
        }
    }
    return nil
}

if err := validateCSRFTrustedWildcardOrigins(cfg.TrustedOrigins); err != nil { log.Fatal(err) }

Prevention

When it happens

Trigger: Setting TrustedOrigins to a malformed wildcard such as "https://*" (no suffix), "https://*.example.com/admin" (path), or an entry lacking a scheme after wildcard removal.

Common situations: Adding TrustedOrigins to support a SPA on a different domain and using path-scoped values, or pulling the list from an env var that resolves to a placeholder/empty string.

Related errors


AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04). Data as JSON: /data/errors/f2c5cfdc07c5d9db.json. Report an issue: GitHub.