pagehelper-org/Mybatis-PageHelper · error · PageException
count( ) has a risk of SQL injection
Error message
count(${countColumn}) has a risk of SQL injection What it means
Page.setCountColumn validates the column used in the generated count query. Only "0", "*", or a value passing SqlSafeUtil's injection check are allowed; anything else throws a PageException. This protects the count(...) SQL, which cannot use bound parameters for the column list.
Solutions
- Use "*" (default) or "0" or a plain verified column name like "id".
- Sanitize/whitelist the column name before calling setCountColumn.
- If a distinct/expression count is required, write a custom count method in the mapper (count method id via countSuffix) instead of injecting an expression.
- Update config/property value to a simple column identifier.
Example fix
// before
page.setCountColumn(request.getParameter("col"));
// after
String col = request.getParameter("col");
if (col == null || !col.matches("[a-zA-Z0-9_]+")) {
page.setCountColumn("*");
} else {
page.setCountColumn(col);
} Defensive patterns
Strategy: validation
Validate before calling
static void assertSafeCountColumn(String col) {
if (!("*".equals(col) || "0".equals(col) || col.matches("[a-zA-Z0-9_]+"))) {
throw new IllegalArgumentException("unsafe countColumn: " + col);
}
} Type guard
static boolean isSafeCountColumn(String s) {
return "*".equals(s) || "0".equals(s) || (s != null && s.matches("[a-zA-Z0-9_]+"));
} Try / catch
try {
page.setCountColumn(column);
} catch (PageException e) {
log.warn("Rejected countColumn: {}", column, e);
page.setCountColumn("*");
} Prevention
- Default to "*" unless profiling demands a specific count column.
- Whitelist column names instead of accepting user input verbatim.
- For DISTINCT/expression counts, use a dedicated mapper count method instead of countColumn.
- Keep countColumn values in server-side config, not client payloads.
When it happens
Trigger: Calling Page.setCountColumn(String) (or the countColumn(...) helper / PageHelper.skip-style API that sets it) with a value like 'id) FROM users--' or any string containing quotes/comments that SqlSafeUtil rejects.
Common situations: Passing a user-supplied count column from a request parameter, or configuring countColumn in properties with a typo or expression such as 'distinct id' that the safe check flags.
Related errors
- order by [ ] has a risk of SQL injection, if you want to…
- Created Sql Cache [ ] Error
- When using PageHelper, the dialect must be an…
- Make sure that the AutoDialect implementation class
- Class must provide a constructor without parameters
AI-assisted analysis of pagehelper-org/Mybatis-PageHelper@c692616c5b (2026-09-08).
Data as JSON: /api/errors/648e722b746fff6b.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/com/github/pagehelper/Page.java:591
public <E> PageSerializable<E> doSelectPageSerializable(ISelect select) {
select.doSelect();
return (PageSerializable<E>) this.toPageSerializable();
}
public long doCount(ISelect select) {
this.pageSizeZero = true;
this.pageSize = 0;
select.doSelect();
return this.total;
}
public String getCountColumn() {
return countColumn;
}
public void setCountColumn(String countColumn) {
if (!"0".equals(countColumn) && !"*".equals(countColumn) && SqlSafeUtil.check(countColumn)) {
throw new PageException("count(" + countColumn + ") has a risk of SQL injection");
}
this.countColumn = countColumn;
}
public BoundSqlInterceptor getBoundSqlInterceptor() {
return boundSqlInterceptor;
}
public void setBoundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor) {
this.boundSqlInterceptor = boundSqlInterceptor;
}
BoundSqlInterceptor.Chain getChain() {
return chain;
}
void setChain(BoundSqlInterceptor.Chain chain) {
this.chain = chain;View on GitHub (pinned to c692616c5b)