Refuse open listeners and cross-site writes without auth

Why: The embedded tier starts without auth, and nothing checked Origin or Host, so a public bind or a foreign page could call write APIs.
Evidence: go test ./internal/config ./internal/server covering listen policy, origin rejection, and response headers.
Impact: Non-loopback without auth exits before opening the database. HTML artifacts get a sandbox CSP. Reverse proxies must list their public host in allowedHosts.
Refs: feature/sillytavern-review
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-04 17:28:46 +00:00
co-authored by Cursor
parent fd17011047
commit 8eda35f365
8 changed files with 410 additions and 45 deletions
+25 -6
View File
@@ -42,13 +42,15 @@ func main() {
artifacts := fs.String("artifacts", "", "工件对象目录(默认 <data>/artifacts;PG 档多实例时指向共享卷)")
auth := fs.String("auth", "auto", "API key 认证:auto(PG 档开、嵌入式关)| on | off")
instance := fs.String("instance", "", "本进程标识(空 = 主机名:监听地址;启动对账只收口这个实例的 run)")
insecure := fs.Bool("insecure-listen", false, "允许在非回环地址上不开启认证(每次启动都会警告)")
allowedHosts := fs.String("allowed-hosts", "", "逗号分隔的额外主机名,供反向代理的 Host 与 Origin 校验")
fs.Parse(os.Args[1:])
cliSet := map[string]bool{}
fs.Visit(func(f *flag.Flag) { cliSet[f.Name] = true })
cliSet := visited(fs)
resolved, err := config.Load(*cfgFile, os.LookupEnv, config.Config{
Addr: *addr, DataDir: *data, PluginsDir: *pluginsDir, Mock: *mock,
StorageDSN: *dsn, ArtifactsDir: *artifacts, AuthMode: *auth, Instance: *instance,
InsecureListen: *insecure, AllowedHostsRaw: *allowedHosts,
}, cliSet)
if err != nil {
fmt.Fprintln(os.Stderr, "agent-system:", err)
@@ -57,13 +59,29 @@ func main() {
if err := app.Run(app.Options{
Addr: resolved.Addr, DataDir: resolved.DataDir, PluginsDir: resolved.PluginsDir, ForceMock: resolved.Mock,
StorageDSN: resolved.StorageDSN, ArtifactsDir: resolved.ArtifactsDir, AuthMode: resolved.AuthMode,
InstanceID: resolved.Instance,
InstanceID: resolved.Instance, InsecureListen: resolved.InsecureListen, AllowedHosts: resolved.AllowedHosts(),
}); err != nil {
fmt.Fprintln(os.Stderr, "agent-system:", err)
os.Exit(1)
}
}
// visited 把连字符 flag 收成配置字段名,供 Load 的 cliSet 使用。
func visited(fs *flag.FlagSet) map[string]bool {
set := map[string]bool{}
fs.Visit(func(f *flag.Flag) {
name := f.Name
switch name {
case "insecure-listen":
name = "insecureListen"
case "allowed-hosts":
name = "allowedHosts"
}
set[name] = true
})
return set
}
// runConfig:config explain——只读解析诊断(不建库、不写业务目录;DSN 脱敏)。
func runConfig(args []string) int {
if len(args) == 0 || args[0] != "explain" {
@@ -80,13 +98,14 @@ func runConfig(args []string) int {
artifacts := fs.String("artifacts", "", "")
auth := fs.String("auth", "auto", "")
instance := fs.String("instance", "", "")
insecure := fs.Bool("insecure-listen", false, "")
allowedHosts := fs.String("allowed-hosts", "", "")
fs.Parse(args[1:])
cliSet := map[string]bool{}
fs.Visit(func(f *flag.Flag) { cliSet[f.Name] = true })
resolved, err := config.Load(*cfgFile, os.LookupEnv, config.Config{
Addr: *addr, DataDir: *data, PluginsDir: *pluginsDir, Mock: *mock,
StorageDSN: *dsn, ArtifactsDir: *artifacts, AuthMode: *auth, Instance: *instance,
}, cliSet)
InsecureListen: *insecure, AllowedHostsRaw: *allowedHosts,
}, visited(fs))
if err != nil {
fmt.Fprintln(os.Stderr, "agent-system:", err)
return 1