GitHub Security Advisory: GHSA-q4w7-56hr-83rm
Package: github.com/0xJacky/nginx-ui (GO)
Severity: MODERATE (CVSS 6.5)
CWE: CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
Vulnerable versions: <= 2.3.7
Patched in: 2.3.8

Summary: Nginx-UI Settings API Exposes Protected Secrets

Details:
### Summary
The `GetSettings` API handler (`api/settings/settings.go:24-65`) serializes all settings structs to JSON and returns them to authenticated users. Many sensitive fields are tagged with `protected:"true"` - however, this tag is only enforced during writes (via `ProtectedFill` in `SaveSettings`) and is completely ignored during reads. This exposes 40+ protected fields including `JwtSecret` (enabling auth token forgery), `NodeSecret` (enabling cluster node impersonation), OIDC `ClientSecret` (enabling OAuth account takeover), and the IP whitelist configuration.

### Details
#### Vulnerable Code

**`api/settings/settings.go:49-64` - GetSettings serializes all fields**

```go
c.JSON(http.StatusOK, gin.H{
    "app":       cSettings.AppSettings,
    "server":    cSettings.ServerSettings,
    "database":  settings.DatabaseSettings,
    "auth":      settings.AuthSettings,
    "casdoor":   settings.CasdoorSettings,
    "oidc":      settings.OIDCSettings,
    "cert":      settings.CertSettings,
    "http":      settings.HTTPSettings,
    "logrotate": settings.LogrotateSettings,
    "nginx":     settings.NginxSettings,
    "node":      settings.NodeSettings,
    "openai":    settings.OpenAISettings,
    "terminal":  settings.TerminalSettings,
    "webauthn":  settings.WebAuthnSettings,
})
```

Go's `json.Marshal` serializes all exported fields with `json:` tags. The `protected:"true"` struct tag is a custom tag - it has no effect on JSON serialization.

#### Protection is Write-Only

**`api/settings/settings.go:126-135` - ProtectedFill only used during saves**

```go
cSettings.ProtectedFill(cSettings.AppSettings, &json.App)
cSettings.ProtectedFill(cSettings.ServerSettings, &json.Server)
cSettings.ProtectedFill(settings.AuthSettings, &json.Auth)
// ... etc
```

`ProtectedFill` prevents overwriting protected fields during `SaveSettings`, but `GetSettings` has no corresponding filter. The protection is asymmetric - secrets can be read but not overwritten.

#### Exposed Protected Fields

**`settings/node.go`:**
- `Secret` (protected) - used for cluster node authentication
- `SkipInstallation` (protected), `Demo` (protected)

**`settings/oidc.go` (all protected):**
- `ClientId`, `ClientSecret`, `Endpoint`, `RedirectUri`, `Scopes`, `Identifier`

**`settings/casdoor.go` (all protected):**
- `Endpoint`, `ExternalUrl`, `ClientId`, `ClientSecret`, `CertificatePath`, `Organization`, `Application`, `RedirectUri`

**`settings/auth.go`:**
- `IPWhiteList` (protected) - exposes security configuration

#### Attack Scenario

1. Low-privilege authenticated user calls `GET /api/settings`
2. Response includes `NodeSecret` - attacker can impersonate cluster nodes
3. Response includes OIDC `ClientSecret` - attacker can perform OAuth flows as the application
4. Response includes `IPWhiteList` - attacker learns network security configuration
5. If `JwtSecret` is in app settings (via cosy framework), attacker can forge authentication tokens for any user

### PoC
**1. `GetS