baomidou/mybatis-plus · error · MybatisPlusException
Discovering SQL injection column: %s
Error message
Discovering SQL injection column: %s
What it means
QueryWrapper.checkSqlInjection() opted this wrapper into SQL-injection screening, and a column name passed to the wrapper (via select/orderBy/groupBy/eq column args, etc.) matched known injection patterns in SqlInjectionUtils. MyBatis-Plus then refuses to build the statement because the 'column' does not look like an identifier.
Source
Thrown at mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/conditions/query/QueryWrapper.java:103
/**
* 检查 SQL 注入过滤
*/
private boolean checkSqlInjection;
/**
* 开启检查 SQL 注入
*/
public QueryWrapper<T> checkSqlInjection() {
this.checkSqlInjection = true;
return this;
}
@Override
protected String columnToString(String column) {
if (checkSqlInjection && SqlInjectionUtils.check(column)) {
throw new MybatisPlusException("Discovering SQL injection column: " + column);
}
return column;
}
@Override
public QueryWrapper<T> select(boolean condition, List<String> columns) {
if (condition && CollectionUtils.isNotEmpty(columns)) {
this.sqlSelect.setStringValue(String.join(StringPool.COMMA, columns));
}
return typedThis;
}
@Override
public QueryWrapper<T> select(Class<T> entityClass, Predicate<TableFieldInfo> predicate) {
super.setEntityClass(entityClass);
this.sqlSelect.setStringValue(TableInfoHelper.getTableInfo(getEntityClass()).chooseSelect(predicate));
return typedThis;
}View on GitHub (pinned to bf67d90747)
Solutions
- Never feed user input into column positions; map allowed sort fields through a whitelist of known column names
- If the column is genuinely a legal identifier flagged by the checker, quote it using the database's identifier quoting (e.g. backticks via the column-format feature) or rename it
- Keep checkSqlInjection() enabled — it is doing its job; fix the data flow instead of disabling the check
Example fix
// before
String sort = request.getParameter("sort");
qw.checkSqlInjection().orderByAsc(sort);
// after
Set<String> ALLOWED = Set.of("id", "name", "created_at");
String col = ALLOWED.contains(request.getParameter("sort")) ? request.getParameter("sort") : "id";
qw.checkSqlInjection().orderByAsc(col); Defensive patterns
Strategy: validation
Validate before calling
private static final Set<String> SORTABLE = Set.of("id", "name", "created_at");
private String safeColumn(String input) {
if (!SORTABLE.contains(input)) throw new IllegalArgumentException("Illegal sort column: " + input);
return input;
}
// then: qw.checkSqlInjection().orderByAsc(safeColumn(request.getParameter("sort"))); Try / catch
try { qw.checkSqlInjection().orderByAsc(col); } catch (MybatisPlusException e) { // treat as bad request, log security event audit.warn("Rejected column {}", col); throw new BadRequestException("Invalid sort field"); } Prevention
- Never let request parameters reach column positions unfiltered
- Keep checkSqlInjection() enabled on wrappers built from external input
- Map external field names to internal columns via an explicit whitelist map
When it happens
Trigger: Calling queryWrapper.checkSqlInjection() and then passing a non-identifier string as a column, e.g. "id; DROP TABLE user", "name" -- comment", or user-supplied input directly as a sort column expression.
Common situations: Passing an HTTP request parameter (e.g. a dynamic ORDER BY field from the front end) straight into orderByAsc/last; concatenating user input into column names; legitimately exotic column names containing characters the checker flags.
Related errors
- Discovering SQL injection column: %s
- %s already contains value for %s
- %s does not contain value for %s
- %s is ambiguous in %s (try using the full name including the
- Should be specified either value() or name() attribute in th
AI-assisted analysis of baomidou/mybatis-plus@bf67d90747 (2026-08-14).
Data as JSON: /api/errors/72232f9885741536.
Report an issue: GitHub.