package rules import ( "go/ast" "go/token" "strings" ) // The web/mw CORS convention: mw.CORS uses exact-origin matching and rejects "*" // at construction (panic). Passing "*" is the trap this rule catches before runtime — // allow-all is done with mw.CORSAllowAll(), gated by env in application code. func init() { registered = append(registered, Rule{ ID: "cors.wildcard-noop", Severity: SeverityError, Module: "web", Check: checkCORSWildcard, }, ) } // checkCORSWildcard flags any call to .CORS(...) whose arguments contain a // "*" string literal — which mw.CORS rejects (panics) at boot. func checkCORSWildcard(c *Context) []Finding { var hits []Finding ast.Inspect(c.File, func(n ast.Node) bool { call, ok := n.(*ast.CallExpr) if !ok || !strings.HasSuffix(exprName(call.Fun), ".CORS") { return true } for _, arg := range call.Args { ast.Inspect(arg, func(m ast.Node) bool { lit, ok := m.(*ast.BasicLit) if ok && lit.Kind == token.STRING && strings.Trim(lit.Value, `"`) == "*" { hits = append(hits, Finding{ Message: `mw.CORS with "*" panics at construction — "*" matches no real origin (exact-match only)`, Hint: "Use mw.CORSAllowAll() for local development, or list explicit origins.", Line: c.Fset.Position(call.Pos()).Line, }) } return true }) } return true }) return hits }