You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 563daa1
Browse filesBrowse the repository at this point in the historyBrowse files
fix(security): remediate CodeQL ReDoS, SQL injection, and CLI-injection alerts
Addresses the remaining open code-scanning alerts on main. The 138 alerts
were only 5 rules; 118 were a single mechanical pattern.
polynomial-redos (118): almost all were s.matches(".*RE.*"). String.matches
already anchors, so the wrapping .* exists only to undo that anchoring, and
.* plus an alternation is what backtracks. Rewritten to
PatternUtil.containsPattern (find() over a cached Pattern) at 174 sites in
17 files -- more than the 118 flagged, since CodeQL only reports where taint
reaches, and the untainted ones are the same hazard. Equivalence was checked
by differential test over all 175 literals rather than by inspection.
This changes behavior on multi-line input: `.` does not cross a newline, so
the anchored form failed to match a keyword after a line break and find()
matches it. That is a fix for intent classifiers, and only affects callers
that do not pre-normalize.
The rest were compiled Pattern constants with ambiguous quantifiers, fixed
individually with possessive quantifiers or bounded gaps. PlanPatternLibrary
also had a latent bug: [^from]+ is a character class, so any column with f,
r, o or m in it (order_id) defeated the collapse.
sql-injection (15): three different cases. CardinalityEstimationService was
a real hole -- quoteIdentifier wrapped in quotes without doubling an embedded
quote, so a table named `x" ; DROP TABLE users; --` escaped it. Four of the
five other quoteIdentifier implementations here already escape correctly. It
now delegates to the dialect's SamplingProvider (removing an if/else on
dbType) and resolves both identifiers against information_schema first.
MySQLPrivilegeCheckProvider concatenated a database name into a literal; now
bound. QueryExecutorService and the EXPLAIN providers execute user SQL by
design -- that is the Editor, guarded by the policy layer, not parameterizable.
spring-disabled-csrf-protection: correct as-is; every route is STATELESS with
header-carried tokens, so there is no cookie session to forge. Documented in
place rather than changed.
command-line-injection: spawn already passed array args, but authorize_url
comes from a server response and the win32 branch goes through cmd. Now
scheme-validated to http/https.
Verified: full backend suite shows the same 13 failures / 4 errors as the
untouched baseline (confirmed by stashing) -- no new regressions. 25 new/
touched unit tests and 259 MCP tests pass.
if (!normalized.matches(".*\\b(table|tables|view|views|column|columns|fields|schema|structure|describe|definition)\\b.*")) {
242
+
if (!PatternUtil.containsPattern(normalized, "\\b(table|tables|view|views|column|columns|fields|schema|structure|describe|definition)\\b")) {
242
243
returnfalse;
243
244
}
244
245
// Superlatives and rankings are not exact-schema lookups; neither is design advice.
245
246
// "Which tables should I use to build an accounts module?" names tables but wants
246
247
// reasoning over the schema, not a listing of it — answering it from cached
247
248
// metadata drops exactly the part the user asked for.
248
-
if (normalized.matches(".*\\b(least|most|best|worst|top|bottom|largest|smallest|used|unused|slow|growth|performance|fact|dimension|pattern|relationship|join)\\b.*")
if (PatternUtil.containsPattern(normalized, "\\b(least|most|best|worst|top|bottom|largest|smallest|used|unused|slow|growth|performance|fact|dimension|pattern|relationship|join)\\b")
0 commit comments