Root cause
Authentication & access control
The AI-assisted change below is where the vulnerable behavior appears.
How AI contributed: Flawed AI-written codePublished Aug 25, 2026 in
lin-snow/ech0
Provisional finding. Full causal and release verification remains incomplete.
AI-assisted scope hardening on the user-list route left ordinary sessions exempt from capability checks and relied on an administrator check that the existing service did not perform. The exposure predated that hardening. Other dashboard routes and the separate WebSocket log path also lack required role authorization, but those independent omissions are not attributed to this change.
Root cause
The AI-assisted change below is where the vulnerable behavior appears.
Fix status
No minimum fix commit has been established for this finding.
Fix status unresolved
Case facts
@@ -0,0 +13,10 @@++func RequireScopes(scopes ...string) gin.HandlerFunc {+ return func(ctx *gin.Context) {+ v := viewer.MustFromContext(ctx.Request.Context())+ if v.TokenType() == authModel.TokenTypeSession {+ ctx.Next()+ return+ }+ if v.TokenType() != authModel.TokenTypeAccess {+ ctx.JSON(@@ -26,10 +27,8 @@ ) // Auth- appRouterGroup.AuthRouterGroup.GET("/allusers", h.UserHandler.GetAllUsers())- appRouterGroup.AuthRouterGroup.GET("/user", h.UserHandler.GetUserInfo())- appRouterGroup.AuthRouterGroup.PUT("/user", h.UserHandler.UpdateUser())- appRouterGroup.AuthRouterGroup.DELETE("/user/:id", h.UserHandler.DeleteUser())- appRouterGroup.AuthRouterGroup.PUT("/user/admin/:id", h.UserHandler.UpdateUserAdmin())- appRouterGroup.AuthRouterGroup.POST("/oauth/:provider/bind", h.UserHandler.OAuthBind())- appRouterGroup.AuthRouterGroup.GET("/oauth/info", h.UserHandler.GetOAuthInfo())+ appRouterGroup.AuthRouterGroup.GET(+ "/allusers",+ middleware.RequireScopes(authModel.ScopeAdminUser),+ h.UserHandler.GetAllUsers(),+ )@@ -402,8 +402,18 @@ // 返回: // - []model.User: 用户列表(不包含密码信息) // - error: 获取过程中的错误信息-func (userService *UserService) GetAllUsers() ([]model.User, error) {- allures, err := userService.userRepository.GetAllUsers(context.Background())+func (userService *UserService) GetAllUsers(ctx context.Context) ([]model.User, error) {+ // Only Admin can get all users+ userid := viewer.MustFromContext(ctx).UserID()+ caller, err := userService.userRepository.GetUserByID(ctx, userid)+ if err != nil {+ return nil, err+ }+ if !caller.IsAdmin {+ return nil, errors.New(commonModel.NO_PERMISSION_DENIED)+ }++ allures, err := userService.userRepository.GetAllUsers(ctx) if err != nil { return nil, err }