mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 14:16:08 +00:00
feat(providers): allow provider_type changes on update with SSRF re-validation
Remove blanket rejection of provider_type on update. Instead, when provider_type changes, re-validate the existing api_base against the new type to prevent SSRF via ACP→non-ACP type switch. This enables provider type changes in onboarding/setup flows while maintaining security: ACP providers skip URL validation, so switching from ACP to another type now forces URL re-validation.
This commit is contained in:
1 parent
9fd9e1f47b
commit
abcb9614bc
1 file changed
+13
-7
@@ -376,13 +376,6 @@ func (h *ProvidersHandler) handleUpdateProvider(w http.ResponseWriter, r *http.R
|
||||
}
|
||||
}
|
||||
|
||||
// provider_type is immutable after creation — changing it would bypass
|
||||
// security checks (e.g. ACP skips URL validation). Reject if client tries.
|
||||
if _, ok := updates["provider_type"]; ok {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": i18n.T(locale, i18n.MsgInvalidRequest, "provider_type cannot be changed after creation")})
|
||||
return
|
||||
}
|
||||
|
||||
// Strip masked API key — don't overwrite real value with "***"
|
||||
if apiKey, ok := updates["api_key"]; ok {
|
||||
if s, _ := apiKey.(string); s == "***" || s == "" {
|
||||
@@ -415,6 +408,9 @@ func (h *ProvidersHandler) handleUpdateProvider(w http.ResponseWriter, r *http.R
|
||||
if displayName, ok := updates["display_name"].(string); ok {
|
||||
candidate.DisplayName = displayName
|
||||
}
|
||||
if pt, ok := updates["provider_type"].(string); ok && pt != "" {
|
||||
candidate.ProviderType = pt
|
||||
}
|
||||
if settings, ok := updates["settings"]; ok {
|
||||
rawSettings, err := marshalJSONRaw(settings)
|
||||
if err != nil {
|
||||
@@ -424,6 +420,11 @@ func (h *ProvidersHandler) handleUpdateProvider(w http.ResponseWriter, r *http.R
|
||||
candidate.Settings = rawSettings
|
||||
}
|
||||
|
||||
// Re-validate URLs against the (possibly new) provider type.
|
||||
// When provider_type changes, existing api_base must also pass validation
|
||||
// for the new type — prevents SSRF via ACP→non-ACP type switch.
|
||||
typeChanged := candidate.ProviderType != currentProvider.ProviderType
|
||||
|
||||
if apiBase, ok := updates["api_base"]; ok {
|
||||
if s, _ := apiBase.(string); s != "" {
|
||||
if err := validateProviderURL(s, candidate.ProviderType); err != nil {
|
||||
@@ -431,6 +432,11 @@ func (h *ProvidersHandler) handleUpdateProvider(w http.ResponseWriter, r *http.R
|
||||
return
|
||||
}
|
||||
}
|
||||
} else if typeChanged && candidate.APIBase != "" {
|
||||
if err := validateProviderURL(candidate.APIBase, candidate.ProviderType); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
if baseURL, ok := updates["base_url"]; ok {
|
||||
if s, _ := baseURL.(string); s != "" {
|
||||
|
||||
Reference in new issue
Block a user