← All articles

CVE-2026-19583: Turning Velociraptor Client Monitoring into Recurring Fleet Execution

An investigator could bypass artifact type and EXECVE checks by placing an ordinary executable artifact in the client-monitoring table.

CVE
CVE-2026-19583
Product
Rapid7 Velociraptor
Affected versions
Linux releases before 0.77.2
Fixed versions
0.77.2
Status
Patched
9.9/ 10

CVSS 3.1 Base score

Critical

Rapid7 (CNA) score
Scoring details

Published vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L

CVSS is owned by FIRST and used by permission.

The short version

Velociraptor 0.77.1 enforced EXECVE when an investigator collected Linux.Sys.BashShell normally, but failed to enforce it when the same artifact was installed as a client-monitoring query. A stock investigator could cause a command to run repeatedly on selected endpoints-or across an organization-as the Velociraptor agent account.

The vulnerability was fixed before 0.77.2 and is tracked as CVE-2026-19583.

At a glance

Field Detail
Tested version Velociraptor 0.77.1, commit 3137c7f71
Fixed version 0.77.2
Vulnerability class Incorrect permission assignment, CWE-732
Vendor affected range Velociraptor on Linux before 0.77.2
Required access Stock investigator with COLLECT_CLIENT
Demonstrated impact Recurring endpoint commands as the agent account
Researcher estimate Critical; proposed CVSS 3.1 score 9.9
Credits Yuval Miller and Leon Kayaliev

Normal collection versus monitoring

The shipped Linux.Sys.BashShell artifact requires EXECVE. An investigator normally has permission to collect safe client artifacts, but not to execute arbitrary commands. The ordinary collection path enforced that distinction.

Client monitoring follows a different path. It stores queries that endpoints run continuously and can target an entire organization or a labeled subset. That made a missing permission check particularly consequential: the bypass was persistent and could become fleet-wide.

Why I started with a negative control

The direct collection denial established that the role and artifact metadata were configured correctly: the investigator really lacked EXECVE, and Linux.Sys.BashShell really required it. I then changed only the dispatch path. That made the result an authorization inconsistency rather than a debate about the stock role definition.

I used a temporary endpoint label and recorded the existing monitoring table before the test. SetClientMonitoringState replaces the complete table, so a careless reproduction could disrupt legitimate monitoring. The label also kept the proof to one disposable client even though the vulnerable primitive could be applied organization-wide.

Reproduction

The actor had only the stock investigator role. Direct collection provided the negative control:

SELECT collect_client(
  client_id='CLIENT_ID',
  artifacts=['Linux.Sys.BashShell'])
FROM scope()

Velociraptor rejected this with an EXECVE permission error.

For a bounded demonstration, the disposable endpoint was assigned a temporary label. The investigator then used set_client_monitoring() or the equivalent SetClientMonitoringState API to install an ordinary client artifact in the label-specific monitoring table:

{
  "artifacts": {"artifacts": []},
  "label_events": [{
    "label": "esc",
    "artifacts": {
      "artifacts": ["Linux.Sys.BashShell"],
      "specs": [{
        "artifact": "Linux.Sys.BashShell",
        "parameters": {"env": [
          {"key": "Command", "value": "echo UNIQUE_MARKER; /usr/bin/id"},
          {"key": "Stateful", "value": "N"}
        ]}
      }]
    }
  }]
}

The update was accepted without an EXECVE denial or artifact-type error. The endpoint began the monitoring query, and its results contained the unique marker and real id output. The test agent intentionally ran as an ordinary lab user; production agents commonly run as root on Linux or SYSTEM on Windows.

Removing the label condition would have applied the monitoring query across the organization. The original monitoring table, label, and proof artifact were restored or removed after testing.

Root cause

Two controls were missing:

  1. services/client_monitoring/client_monitoring.go compiled monitoring artifacts with NullACLManager, whose access checks always succeeded. Required permissions declared by the artifact were therefore bypassed.
  2. Only one helper verified that a monitoring artifact had the CLIENT_EVENT type. The shared state-setting service and API accepted an ordinary CLIENT artifact supplied in a complete monitoring table.

The application enforced the security rule at one entry point rather than at the shared state-changing boundary.

Code path

The vulnerable path lives in services/client_monitoring/client_monitoring.go. compileArtifactCollectorArgs() constructed the launcher compiler with NullACLManager. That object deliberately approves access checks, so artifact requirements such as EXECVE had no relationship to the user modifying the monitoring table.

compileState() applied that compiler to global and label-specific entries. setClientMonitoringState() then cloned and stored the complete table without requiring every submitted artifact to be a CLIENT_EVENT artifact or checking the caller against each artifact’s declared permissions.

The direct and monitoring paths therefore reached the same behavior under different authority:

direct collection -> investigator ACL manager -> EXECVE denied
monitoring update  -> NullACLManager           -> EXECVE accepted

Because the API replaces the complete monitoring table, authorization must cover every artifact in the proposed state, not only the newly added row. This also explains an operational consequence of the fix: a user changing one entry must have the permissions required by existing entries they resubmit.

Detection notes

Audit changes to client-monitoring state and flag ordinary CLIENT artifacts where only CLIENT_EVENT artifacts should appear. Any executable artifact-such as Linux.Sys.BashShell-in monitoring state is high priority.

Correlate the modifying principal, its permissions at the time, the labels or organization scope, and subsequent monitoring results. A monitoring change followed by shell output or process creation across several endpoints is more meaningful than either signal alone.

Remediation

Upgrade to Velociraptor 0.77.2 or later. Monitoring changes should be compiled with an ACL manager bound to the modifying principal. The shared SetClientMonitoringState service should validate artifact type and the full set of required permissions so every API and VQL entry point receives the same enforcement.

The vendor fix in c0c9dd60 replaces NullACLManager with NewServerACLManager(config, principal) and adds a validation pass before storage. The new check rejects artifacts whose type is not MODE_CLIENT_EVENT and calls the launcher access check for every artifact. A rejected update is stopped before the table is cloned and persisted.

Disclosure timeline

Date Event
2026-08-05 Vulnerability reported to Rapid7
2026-09-10 Rapid7 published CVE-2026-19583

References