{"record":{"id":"72232f9885741536","repo":"baomidou/mybatis-plus","slug":"discovering-sql-injection-column-s","errorCode":null,"errorMessage":"Discovering SQL injection column: %s","messagePattern":"Discovering SQL injection column: (.+?)","errorType":"exception","errorClass":"MybatisPlusException","httpStatus":null,"severity":"error","filePath":"mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/conditions/query/QueryWrapper.java","lineNumber":103,"sourceCode":"\n\n    /**\n     * 检查 SQL 注入过滤\n     */\n    private boolean checkSqlInjection;\n\n    /**\n     * 开启检查 SQL 注入\n     */\n    public QueryWrapper<T> checkSqlInjection() {\n        this.checkSqlInjection = true;\n        return this;\n    }\n\n    @Override\n    protected String columnToString(String column) {\n        if (checkSqlInjection && SqlInjectionUtils.check(column)) {\n            throw new MybatisPlusException(\"Discovering SQL injection column: \" + column);\n        }\n        return column;\n    }\n\n    @Override\n    public QueryWrapper<T> select(boolean condition, List<String> columns) {\n        if (condition && CollectionUtils.isNotEmpty(columns)) {\n            this.sqlSelect.setStringValue(String.join(StringPool.COMMA, columns));\n        }\n        return typedThis;\n    }\n\n    @Override\n    public QueryWrapper<T> select(Class<T> entityClass, Predicate<TableFieldInfo> predicate) {\n        super.setEntityClass(entityClass);\n        this.sqlSelect.setStringValue(TableInfoHelper.getTableInfo(getEntityClass()).chooseSelect(predicate));\n        return typedThis;\n    }","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/baomidou/mybatis-plus/blob/bf67d907478c724120bf76292da54abf9e73c2b3/mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/conditions/query/QueryWrapper.java#L85-L121","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nString sort = request.getParameter(\"sort\");\nqw.checkSqlInjection().orderByAsc(sort);\n// after\nSet<String> ALLOWED = Set.of(\"id\", \"name\", \"created_at\");\nString col = ALLOWED.contains(request.getParameter(\"sort\")) ? request.getParameter(\"sort\") : \"id\";\nqw.checkSqlInjection().orderByAsc(col);","handlingStrategy":"validation","validationCode":"private static final Set<String> SORTABLE = Set.of(\"id\", \"name\", \"created_at\");\nprivate String safeColumn(String input) {\n    if (!SORTABLE.contains(input)) throw new IllegalArgumentException(\"Illegal sort column: \" + input);\n    return input;\n}\n// then: qw.checkSqlInjection().orderByAsc(safeColumn(request.getParameter(\"sort\")));","typeGuard":null,"tryCatchPattern":"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\"); }","preventionTips":["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"],"tags":["security","sql-injection","query-wrapper","mybatis-plus"],"backgroundTag":null,"analyzedSha":"bf67d907478c724120bf76292da54abf9e73c2b3","analyzedAt":"2026-08-14T15:17:09.543Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}