From a4f4cb1f34f1bc5fc26903dd20be0f06a7503c51 Mon Sep 17 00:00:00 2001 From: naiba Date: Tue, 26 May 2026 04:07:49 +0000 Subject: [PATCH] fix(fm): switch create FM session to POST to defeat CSRF GET /api/v1/file?id= created an FM stream on the agent stream and committed real state change (TaskTypeFM dispatched). With JWT cookie SameSite=Lax a victim's browser would still send the cookie on a top-level cross-site GET, so an attacker could trick a logged-in user into opening an FM session on any of their own servers, consuming resources and triggering the agent's FM machinery without consent. Mirror the GHSA-8qhj-4f8c-j8qg fix: move the route to POST. SameSite= Lax cookies are not sent on cross-site POST. Frontend (admin-frontend) adjusted in a follow-up commit. Co-authored-by: cloudcode --- cmd/dashboard/controller/controller.go | 2 +- cmd/dashboard/controller/fm.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/dashboard/controller/controller.go b/cmd/dashboard/controller/controller.go index 7468ce4c..a26f317a 100644 --- a/cmd/dashboard/controller/controller.go +++ b/cmd/dashboard/controller/controller.go @@ -84,7 +84,7 @@ func routers(r *gin.Engine, frontendDist fs.FS) { auth.POST("/terminal", commonHandler(createTerminal)) auth.GET("/ws/terminal/:id", commonHandler(terminalStream)) - auth.GET("/file", commonHandler(createFM)) + auth.POST("/file", commonHandler(createFM)) auth.GET("/ws/file/:id", commonHandler(fmStream)) auth.GET("/profile", commonHandler(getProfile)) diff --git a/cmd/dashboard/controller/fm.go b/cmd/dashboard/controller/fm.go index 638dcb7b..4cb3b078 100644 --- a/cmd/dashboard/controller/fm.go +++ b/cmd/dashboard/controller/fm.go @@ -24,7 +24,7 @@ import ( // @Param id query uint true "Server ID" // @Produce json // @Success 200 {object} model.CreateFMResponse -// @Router /file [get] +// @Router /file [post] func createFM(c *gin.Context) (*model.CreateFMResponse, error) { idStr := c.Query("id") id, err := strconv.ParseUint(idStr, 10, 64)