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

  1. Never feed user input into column positions; map allowed sort fields through a whitelist of known column names
  2. 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
  3. 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

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


AI-assisted analysis of baomidou/mybatis-plus@bf67d90747 (2026-08-14). Data as JSON: /api/errors/72232f9885741536. Report an issue: GitHub.