From a1634b219a4e52813e70ff07e6376a01449c4515 Mon Sep 17 00:00:00 2001 From: Dave Date: Sat, 12 Oct 2024 03:45:47 -0400 Subject: [PATCH] fix: roll out bluemonday Sanitize more widely (#3794) * initial pass: roll out bluemonday sanitization more widely Signed-off-by: Dave Lee * add one additional sanitize - the overall modelslist used by the docs site Signed-off-by: Dave Lee --------- Signed-off-by: Dave Lee --- .github/ci/modelslist.go | 7 +++++++ core/http/elements/gallery.go | 23 ++++++++++------------- core/http/endpoints/openai/assistant.go | 17 +++++++++-------- core/http/endpoints/openai/files.go | 13 +++++++------ core/http/middleware/auth.go | 3 ++- core/http/routes/ui.go | 3 ++- 6 files changed, 37 insertions(+), 29 deletions(-) diff --git a/.github/ci/modelslist.go b/.github/ci/modelslist.go index cdc31703..719cd094 100644 --- a/.github/ci/modelslist.go +++ b/.github/ci/modelslist.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "os" + "github.com/microcosm-cc/bluemonday" "gopkg.in/yaml.v3" ) @@ -279,6 +280,12 @@ func main() { return } + // Ensure that all arbitrary text content is sanitized before display + for i, m := range models { + models[i].Name = bluemonday.StrictPolicy().Sanitize(m.Name) + models[i].Description = bluemonday.StrictPolicy().Sanitize(m.Description) + } + // render the template data := struct { Models []*GalleryModel diff --git a/core/http/elements/gallery.go b/core/http/elements/gallery.go index 91a12310..06076bd9 100644 --- a/core/http/elements/gallery.go +++ b/core/http/elements/gallery.go @@ -6,6 +6,7 @@ import ( "github.com/chasefleming/elem-go" "github.com/chasefleming/elem-go/attrs" + "github.com/microcosm-cc/bluemonday" "github.com/mudler/LocalAI/core/gallery" "github.com/mudler/LocalAI/core/p2p" "github.com/mudler/LocalAI/core/services" @@ -41,7 +42,7 @@ func DoneProgress(galleryID, text string, showDelete bool) string { "tabindex": "-1", "autofocus": "", }, - elem.Text(text), + elem.Text(bluemonday.StrictPolicy().Sanitize(text)), ), elem.If(showDelete, deleteButton(galleryID, modelName), reInstallButton(galleryID)), ).Render() @@ -57,7 +58,7 @@ func ErrorProgress(err, galleryName string) string { "tabindex": "-1", "autofocus": "", }, - elem.Text("Error "+err), + elem.Text("Error "+bluemonday.StrictPolicy().Sanitize(err)), ), installButton(galleryName), ).Render() @@ -170,7 +171,7 @@ func P2PNodeBoxes(nodes []p2p.NodeData) string { attrs.Props{ "class": "text-gray-200 font-semibold ml-2 mr-1", }, - elem.Text(n.ID), + elem.Text(bluemonday.StrictPolicy().Sanitize(n.ID)), ), elem.Text("Status: "), elem.If( @@ -227,7 +228,7 @@ func StartProgressBar(uid, progress, text string) string { "tabindex": "-1", "autofocus": "", }, - elem.Text(text), + elem.Text(bluemonday.StrictPolicy().Sanitize(text)), //Perhaps overly defensive elem.Div(attrs.Props{ "hx-get": "/browse/job/progress/" + uid, "hx-trigger": "every 600ms", @@ -249,9 +250,7 @@ func cardSpan(text, icon string) elem.Node { "class": icon + " pr-2", }), - elem.Text(text), - - //elem.Text(text), + elem.Text(bluemonday.StrictPolicy().Sanitize(text)), ) } @@ -285,11 +284,9 @@ func searchableElement(text, icon string) elem.Node { elem.I(attrs.Props{ "class": icon + " pr-2", }), - elem.Text(text), + elem.Text(bluemonday.StrictPolicy().Sanitize(text)), ), ), - - //elem.Text(text), ) } @@ -303,7 +300,7 @@ func link(text, url string) elem.Node { elem.I(attrs.Props{ "class": "fas fa-link pr-2", }), - elem.Text(text), + elem.Text(bluemonday.StrictPolicy().Sanitize(text)), ) } func installButton(galleryName string) elem.Node { @@ -387,13 +384,13 @@ func ListModels(models []*gallery.GalleryModel, processTracker ProcessTracker, g attrs.Props{ "class": "mb-2 text-xl font-bold leading-tight", }, - elem.Text(m.Name), + elem.Text(bluemonday.StrictPolicy().Sanitize(m.Name)), ), elem.P( attrs.Props{ "class": "mb-4 text-sm [&:not(:hover)]:truncate text-base", }, - elem.Text(m.Description), + elem.Text(bluemonday.StrictPolicy().Sanitize(m.Description)), ), ) } diff --git a/core/http/endpoints/openai/assistant.go b/core/http/endpoints/openai/assistant.go index 3240e8ee..1d83066a 100644 --- a/core/http/endpoints/openai/assistant.go +++ b/core/http/endpoints/openai/assistant.go @@ -10,6 +10,7 @@ import ( "time" "github.com/gofiber/fiber/v2" + "github.com/microcosm-cc/bluemonday" "github.com/mudler/LocalAI/core/config" "github.com/mudler/LocalAI/core/schema" "github.com/mudler/LocalAI/core/services" @@ -83,7 +84,7 @@ func CreateAssistantEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoad if !modelExists(cl, ml, request.Model) { log.Warn().Msgf("Model: %s was not found in list of models.", request.Model) - return c.Status(fiber.StatusBadRequest).SendString("Model " + request.Model + " not found") + return c.Status(fiber.StatusBadRequest).SendString(bluemonday.StrictPolicy().Sanitize(fmt.Sprintf("Model %q not found", request.Model))) } if request.Tools == nil { @@ -147,7 +148,7 @@ func ListAssistantsEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoade // Convert string limit to integer limit, err := strconv.Atoi(limitQuery) if err != nil { - return c.Status(http.StatusBadRequest).SendString(fmt.Sprintf("Invalid limit query value: %s", limitQuery)) + return c.Status(http.StatusBadRequest).SendString(bluemonday.StrictPolicy().Sanitize(fmt.Sprintf("Invalid limit query value: %s", limitQuery))) } // Sort assistants @@ -288,7 +289,7 @@ func GetAssistantEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, } } - return c.Status(fiber.StatusNotFound).SendString(fmt.Sprintf("Unable to find assistant with id: %s", assistantID)) + return c.Status(fiber.StatusNotFound).SendString(bluemonday.StrictPolicy().Sanitize(fmt.Sprintf("Unable to find assistant with id: %s", assistantID))) } } @@ -337,11 +338,11 @@ func CreateAssistantFileEndpoint(cl *config.BackendConfigLoader, ml *model.Model } } - return c.Status(fiber.StatusNotFound).SendString(fmt.Sprintf("Unable to find file_id: %s", request.FileID)) + return c.Status(fiber.StatusNotFound).SendString(bluemonday.StrictPolicy().Sanitize(fmt.Sprintf("Unable to find file_id: %s", request.FileID))) } } - return c.Status(fiber.StatusNotFound).SendString(fmt.Sprintf("Unable to find %q", assistantID)) + return c.Status(fiber.StatusNotFound).SendString(bluemonday.StrictPolicy().Sanitize(fmt.Sprintf("Unable to find %q", assistantID))) } } @@ -442,7 +443,7 @@ func ModifyAssistantEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoad return c.Status(fiber.StatusOK).JSON(newAssistant) } } - return c.Status(fiber.StatusNotFound).SendString(fmt.Sprintf("Unable to find assistant with id: %s", assistantID)) + return c.Status(fiber.StatusNotFound).SendString(bluemonday.StrictPolicy().Sanitize(fmt.Sprintf("Unable to find assistant with id: %s", assistantID))) } } @@ -513,9 +514,9 @@ func GetAssistantFileEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoa if assistantFile.ID == fileId { return c.Status(fiber.StatusOK).JSON(assistantFile) } - return c.Status(fiber.StatusNotFound).SendString(fmt.Sprintf("Unable to find assistant file with file_id: %s", fileId)) + return c.Status(fiber.StatusNotFound).SendString(bluemonday.StrictPolicy().Sanitize(fmt.Sprintf("Unable to find assistant file with file_id: %s", fileId))) } } - return c.Status(fiber.StatusNotFound).SendString(fmt.Sprintf("Unable to find assistant file with assistant_id: %s", assistantID)) + return c.Status(fiber.StatusNotFound).SendString(bluemonday.StrictPolicy().Sanitize(fmt.Sprintf("Unable to find assistant file with assistant_id: %s", assistantID))) } } diff --git a/core/http/endpoints/openai/files.go b/core/http/endpoints/openai/files.go index 903484b4..bc392e73 100644 --- a/core/http/endpoints/openai/files.go +++ b/core/http/endpoints/openai/files.go @@ -8,6 +8,7 @@ import ( "sync/atomic" "time" + "github.com/microcosm-cc/bluemonday" "github.com/mudler/LocalAI/core/config" "github.com/mudler/LocalAI/core/schema" @@ -49,7 +50,7 @@ func UploadFilesEndpoint(cm *config.BackendConfigLoader, appConfig *config.Appli err = c.SaveFile(file, savePath) if err != nil { - return c.Status(fiber.StatusInternalServerError).SendString("Failed to save file: " + err.Error()) + return c.Status(fiber.StatusInternalServerError).SendString("Failed to save file: " + bluemonday.StrictPolicy().Sanitize(err.Error())) } f := schema.File{ @@ -121,7 +122,7 @@ func GetFilesEndpoint(cm *config.BackendConfigLoader, appConfig *config.Applicat return func(c *fiber.Ctx) error { file, err := getFileFromRequest(c) if err != nil { - return c.Status(fiber.StatusInternalServerError).SendString(err.Error()) + return c.Status(fiber.StatusInternalServerError).SendString(bluemonday.StrictPolicy().Sanitize(err.Error())) } return c.JSON(file) @@ -143,14 +144,14 @@ func DeleteFilesEndpoint(cm *config.BackendConfigLoader, appConfig *config.Appli return func(c *fiber.Ctx) error { file, err := getFileFromRequest(c) if err != nil { - return c.Status(fiber.StatusInternalServerError).SendString(err.Error()) + return c.Status(fiber.StatusInternalServerError).SendString(bluemonday.StrictPolicy().Sanitize(err.Error())) } err = os.Remove(filepath.Join(appConfig.UploadDir, file.Filename)) if err != nil { // If the file doesn't exist then we should just continue to remove it if !errors.Is(err, os.ErrNotExist) { - return c.Status(fiber.StatusInternalServerError).SendString(fmt.Sprintf("Unable to delete file: %s, %v", file.Filename, err)) + return c.Status(fiber.StatusInternalServerError).SendString(bluemonday.StrictPolicy().Sanitize(fmt.Sprintf("Unable to delete file: %s, %v", file.Filename, err))) } } @@ -180,12 +181,12 @@ func GetFilesContentsEndpoint(cm *config.BackendConfigLoader, appConfig *config. return func(c *fiber.Ctx) error { file, err := getFileFromRequest(c) if err != nil { - return c.Status(fiber.StatusInternalServerError).SendString(err.Error()) + return c.Status(fiber.StatusInternalServerError).SendString(bluemonday.StrictPolicy().Sanitize(err.Error())) } fileContents, err := os.ReadFile(filepath.Join(appConfig.UploadDir, file.Filename)) if err != nil { - return c.Status(fiber.StatusInternalServerError).SendString(err.Error()) + return c.Status(fiber.StatusInternalServerError).SendString(bluemonday.StrictPolicy().Sanitize(err.Error())) } return c.Send(fileContents) diff --git a/core/http/middleware/auth.go b/core/http/middleware/auth.go index d2152e9b..8f5fe2fb 100644 --- a/core/http/middleware/auth.go +++ b/core/http/middleware/auth.go @@ -7,6 +7,7 @@ import ( "github.com/dave-gray101/v2keyauth" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/keyauth" + "github.com/microcosm-cc/bluemonday" "github.com/mudler/LocalAI/core/config" ) @@ -38,7 +39,7 @@ func getApiKeyErrorHandler(applicationConfig *config.ApplicationConfig) fiber.Er if applicationConfig.OpaqueErrors { return ctx.SendStatus(403) } - return ctx.Status(403).SendString(err.Error()) + return ctx.Status(403).SendString(bluemonday.StrictPolicy().Sanitize(err.Error())) } if applicationConfig.OpaqueErrors { return ctx.SendStatus(500) diff --git a/core/http/routes/ui.go b/core/http/routes/ui.go index cfe9368c..6ea38f35 100644 --- a/core/http/routes/ui.go +++ b/core/http/routes/ui.go @@ -6,6 +6,7 @@ import ( "sort" "strings" + "github.com/microcosm-cc/bluemonday" "github.com/mudler/LocalAI/core/config" "github.com/mudler/LocalAI/core/gallery" "github.com/mudler/LocalAI/core/http/elements" @@ -171,7 +172,7 @@ func RegisterUIRoutes(app *fiber.App, Search string `form:"search"` }{} if err := c.BodyParser(&form); err != nil { - return c.Status(fiber.StatusBadRequest).SendString(err.Error()) + return c.Status(fiber.StatusBadRequest).SendString(bluemonday.StrictPolicy().Sanitize(err.Error())) } models, _ := gallery.AvailableGalleryModels(appConfig.Galleries, appConfig.ModelPath)