labstack/echo · error

* as allowed origin and AllowCredentials=true is insecure an

Error message

* as allowed origin and AllowCredentials=true is insecure and not allowed. Use custom UnsafeAllowOriginFunc

What it means

Returned by CORSConfig.ToMiddleware when AllowOrigins contains the wildcard "*" and AllowCredentials is true. Browsers themselves reject Access-Control-Allow-Origin: * combined with credentials, so this configuration can never work and Echo blocks it at wiring time as a deliberate safety guard. Use a custom UnsafeAllowOriginFunc to reflect the request Origin when you need credentialed CORS.

Source

Thrown at middleware/cors.go:180

	allowMethods := strings.Join(config.AllowMethods, ",")
	allowHeaders := strings.Join(config.AllowHeaders, ",")
	exposeHeaders := strings.Join(config.ExposeHeaders, ",")

	maxAge := "0"
	if config.MaxAge > 0 {
		maxAge = strconv.Itoa(config.MaxAge)
	}

	allowOriginFunc := config.UnsafeAllowOriginFunc
	if config.UnsafeAllowOriginFunc == nil {
		if len(config.AllowOrigins) == 0 {
			return nil, errors.New("at least one AllowOrigins is required or UnsafeAllowOriginFunc must be provided")
		}
		allowOriginFunc = config.defaultAllowOriginFunc
		for _, origin := range config.AllowOrigins {
			if origin == "*" {
				if config.AllowCredentials {
					return nil, fmt.Errorf("* as allowed origin and AllowCredentials=true is insecure and not allowed. Use custom UnsafeAllowOriginFunc")
				}
				allowOriginFunc = config.starAllowOriginFunc
				break
			}
			if err := validateOrigin(origin, "allow origin"); err != nil {
				return nil, err
			}
		}
		config.AllowOrigins = append([]string(nil), config.AllowOrigins...)
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c *echo.Context) error {
			if config.Skipper(c) {
				return next(c)
			}

			req := c.Request()

View on GitHub (pinned to 05489dc173)

Solutions

  1. If you do not need cookies/credentials, remove AllowCredentials (leave it false) and keep the wildcard.
  2. If you need credentials, list explicit origins instead of the wildcard.
  3. If the allowed set is dynamic, provide UnsafeAllowOriginFunc that validates the request Origin and returns it reflected; this bypasses the wildcard check.
  4. Never echo the Origin unchecked — validate against an allowlist to avoid CORS reflection attacks.

Example fix

// before
m := middleware.CORSWithConfig(middleware.CORSConfig{
    AllowOrigins:     []string{"*"},
    AllowCredentials: true,
})
// after
m := middleware.CORSWithConfig(middleware.CORSConfig{
    AllowOrigins:     []string{"https://app.example.com", "https://admin.example.com"},
    AllowCredentials: true,
})
Defensive patterns

Strategy: validation

Validate before calling

func corsMiddleware(allowAll bool, creds bool, allowed []string) (echo.MiddlewareFunc, error) {
    hasWildcard := false
    for _, o := range allowed {
        if o == "*" { hasWildcard = true }
    }
    if hasWildcard && creds {
        return nil, errors.New("refusing wildcard origin with AllowCredentials; use explicit origins or UnsafeAllowOriginFunc")
    }
    return middleware.CORSConfig{AllowOrigins: allowed, AllowCredentials: creds}.ToMiddleware()
}

Prevention

When it happens

Trigger: CORSConfig{AllowOrigins: []string{"*"}, AllowCredentials: true}, or CORS("*") combined with a config that sets AllowCredentials=true.

Common situations: Developer wants 'allow everyone with cookies' and reaches for the wildcard; copy-pasting a permissive CORS config into an authenticated API; or enabling AllowCredentials globally while debugging and forgetting to narrow origins.

Related errors


AI-assisted analysis of labstack/echo@05489dc173 (2026-08-04). Data as JSON: /data/errors/d6ccdd198160cd7f.json. Report an issue: GitHub.