Rapid7 Velociraptor directory traversal in client ID parameter
Description
Rapid7 Velociraptor did not properly sanitize the client ID parameter to the CreateCollection API, allowing a directory traversal in where the collection task could be written. It was possible to provide a client id of "../clients/server" to schedule the collection for the server (as a server artifact), but only require privileges to schedule collections on the client.
Normally, to schedule an artifact on the server, the COLLECT_SERVER permission is required. This permission is normally only granted to "administrator" role. Due to this issue, it is sufficient to have the COLLECT_CLIENT privilege, which is normally granted to the "investigator" role. To exploit this vulnerability, the attacker must already have a Velociraptor user account at least "investigator" level, and be able to authenticate to the GUI and issue an API call to the backend. Typically, most users deploy Velociraptor with limited access to a trusted group, and most users will already be administrators within the GUI.
This issue affects Velociraptor versions before 0.6.7-5. Version 0.6.7-5, released January 16, 2023, fixes the issue.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
www.velocidex.com/golang/velociraptorGo | < 0.6.7-5 | 0.6.7-5 |
Affected products
1- Range: 0
Patches
14718bb0cb426Create a new 0.6.7-5 release (#2385)
7 files changed · +31 −5
constants/constants.go+1 −1 modified@@ -23,7 +23,7 @@ import ( ) const ( - VERSION = "0.6.7-4" + VERSION = "0.6.7-5" ENROLLMENT_WELL_KNOWN_FLOW = "E:Enrol" MONITORING_WELL_KNOWN_FLOW = FLOW_PREFIX + "Monitoring"
paths/constants.go+2 −2 modified@@ -27,10 +27,10 @@ var ( NOTEBOOK_ROOT = path_specs.NewSafeDatastorePath("notebooks"). SetType(api.PATH_TYPE_DATASTORE_JSON) - DOWNLOADS_ROOT = path_specs.NewSafeFilestorePath("downloads"). + DOWNLOADS_ROOT = path_specs.NewUnsafeFilestorePath("downloads"). SetType(api.PATH_TYPE_FILESTORE_DOWNLOAD_ZIP) - CLIENTS_ROOT = path_specs.NewSafeDatastorePath("clients"). + CLIENTS_ROOT = path_specs.NewUnsafeDatastorePath("clients"). SetType(api.PATH_TYPE_DATASTORE_PROTO) CONFIG_ROOT = path_specs.NewSafeDatastorePath("config").
services/indexing/simple.go+1 −1 modified@@ -79,7 +79,7 @@ func (self *Indexer) CheckSimpleIndex( for _, keyword := range keywords { message := &emptypb.Empty{} keyword = strings.ToLower(keyword) - subject := index_urn.AddChild(keyword, entity) + subject := index_urn.AddUnsafeChild(keyword, entity) return db.GetSubject(config_obj, subject, message) } return errors.New("Client does not have label")
services/launcher/launcher.go+5 −0 modified@@ -138,6 +138,7 @@ import ( "www.velocidex.com/golang/velociraptor/logging" "www.velocidex.com/golang/velociraptor/paths" "www.velocidex.com/golang/velociraptor/services" + "www.velocidex.com/golang/velociraptor/utils" vql_subsystem "www.velocidex.com/golang/velociraptor/vql" ) @@ -539,6 +540,10 @@ func (self *Launcher) ScheduleArtifactCollectionFromCollectorArgs( return "", errors.New("Client id not provided.") } + if !utils.ValidateClientId(client_id) { + return "", errors.New("Client id not valid.") + } + db, err := datastore.GetDB(config_obj) if err != nil { return "", err
utils/clientid.go+12 −0 added@@ -0,0 +1,12 @@ +package utils + +import "regexp" + +var ( + // Client IDs always start with "C." or they can refer to the "server" + client_id_regex = regexp.MustCompile("^(C\\.[a-z0-9]+|server)") +) + +func ValidateClientId(client_id string) bool { + return client_id_regex.MatchString(client_id) +}
vql/filesystem/copy.go+9 −0 modified@@ -25,6 +25,7 @@ import ( "github.com/Velocidex/ordereddict" "www.velocidex.com/golang/velociraptor/accessors" + "www.velocidex.com/golang/velociraptor/acls" "www.velocidex.com/golang/velociraptor/artifacts" "www.velocidex.com/golang/velociraptor/utils" vql_subsystem "www.velocidex.com/golang/velociraptor/vql" @@ -109,6 +110,14 @@ func (self *CopyFunction) Call(ctx context.Context, arg.Destination) } + // We are about to write on the filesystem - make sure the user + // has write access. + err = vql_subsystem.CheckAccess(scope, acls.FILESYSTEM_WRITE) + if err != nil { + scope.Log("copy: %s", err.Error()) + return vfilter.Null{} + } + flags := os.O_RDWR | os.O_CREATE | os.O_TRUNC if arg.Append { flags = os.O_WRONLY | os.O_APPEND
vql/server/compress.go+1 −1 modified@@ -42,7 +42,7 @@ func (self *Compress) Call(ctx context.Context, scope vfilter.Scope, args *ordereddict.Dict) vfilter.Any { - err := vql_subsystem.CheckAccess(scope, acls.FILESYSTEM_WRITE) + err := vql_subsystem.CheckAccess(scope, acls.FILESYSTEM_WRITE, acls.FILESYSTEM_READ) if err != nil { scope.Log("compress: %v", err) return vfilter.Null{}
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.