{"record":{"id":"1d8559aec395795b","repo":"baomidou/mybatis-plus","slug":"discovering-sql-injection-column-s-1d8559","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/update/UpdateWrapper.java","lineNumber":90,"sourceCode":"\n\n    /**\n     * 检查 SQL 注入过滤\n     */\n    private boolean checkSqlInjection;\n\n    /**\n     * 开启检查 SQL 注入\n     */\n    public UpdateWrapper<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 String getSqlSet() {\n        if (CollectionUtils.isEmpty(sqlSet)) {\n            return null;\n        }\n        return String.join(Constants.COMMA, sqlSet);\n    }\n\n    @Override\n    public UpdateWrapper<T> set(boolean condition, String column, Object val, String mapping) {\n        return maybeDo(condition, () -> {\n            String sql = formatParam(mapping, val);\n            sqlSet.add(column + Constants.EQUALS + sql);\n        });","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/baomidou/mybatis-plus/blob/bf67d907478c724120bf76292da54abf9e73c2b3/mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/conditions/update/UpdateWrapper.java#L72-L108","documentation":"UpdateWrapper.checkSqlInjection() opted this wrapper into SQL-injection screening, and a column string used in set/eq/condition building matched known injection patterns in SqlInjectionUtils. The wrapper rejects the value before the SQL reaches the database.","triggerScenarios":"Calling updateWrapper.checkSqlInjection() and then passing a suspicious string as a column argument, e.g. set(\"name = 'x', role = 'admin'\", value), or column strings built from raw request input.","commonSituations":"Using UpdateWrapper.set with a combined 'col = expr' string instead of set(column, value); front-end driven field names flowing into update conditions; test data containing quotes/semicolons used as a column name.","solutions":["Use the two-argument form set(\"status\", value) instead of embedding expressions in the column string","Whitelist any dynamic column names coming from external input","For legitimate identifiers flagged by the checker, apply proper DB identifier quoting rather than bypassing the check"],"exampleFix":"// before\nuw.checkSqlInjection().set(\"name='a', role='admin'\", null);\n// after\nuw.checkSqlInjection().set(\"name\", \"a\").set(\"role\", \"admin\");","handlingStrategy":"validation","validationCode":"private static final Set<String> UPDATABLE = Set.of(\"name\", \"email\", \"status\");\nUpdateWrapper<User> uw = new UpdateWrapper<>().checkSqlInjection();\nif (UPDATABLE.contains(field)) uw.set(field, value); else throw new IllegalArgumentException(\"Field not updatable: \" + field);","typeGuard":null,"tryCatchPattern":"try { uw.set(col, val); } catch (MybatisPlusException e) { audit.warn(\"Rejected set column {}\", col); throw new BadRequestException(\"Invalid field\"); }","preventionTips":["Use set(column, value) — never concatenate expressions into the column string","Whitelist any externally influenced column names","Reserve checkSqlInjection-off wrappers for fully internal, constant SQL"],"tags":["security","sql-injection","update-wrapper","mybatis-plus"],"backgroundTag":null,"analyzedSha":"bf67d907478c724120bf76292da54abf9e73c2b3","analyzedAt":"2026-08-14T15:17:09.543Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}