ReDoS (CWE-1333): Bad backtracking in `like()`/`ilike()` query LIKE pattern compilation
Maintainer antworten meist innerhalb von 1 Tag
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 3/5
- Geschätzter Aufwand
- 1-2 Tage
- Anfängerfreundlichkeit
- 64/100
- Issue-Typ
- Bug
- Klarheit
- Größtenteils klar
- Aktivitätsstatus
- Ruhig
- Tech-Stack
- typescript
Rechercherichtung
Beginnen Sie in packages/db/src/query/compiler/evaluators.ts bei evaluateLike() und reproduzieren Sie das bereitgestellte Near-Miss-Muster, um die Verlangsamung zu bestätigen. Überprüfen Sie die Wildcard-Konvertierung und bewahren Sie das bestehende LIKE/ILIKE-Verhalten, während Sie sicherstellen, dass gezielt erstellte Muster kein katastrophales Backtracking auslösen können; fertig ist die Aufgabe, wenn der PoC zügig abgeschlossen wird und das Matching-Verhalten weiterhin durch Tests abgedeckt ist.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
The problem
The like() and ilike() query builder functions convert SQL LIKE wildcards (% → .*) into a RegExp without bounds. A crafted pattern with many % wildcards creates overlapping .* segments that cause catastrophic backtracking on near-matching inputs.
Vulnerable code
File: packages/db/src/query/compiler/evaluators.ts (lines 632-655)
function evaluateLike(
value: any,
pattern: any,
caseInsensitive: boolean,
): boolean {
if (typeof value !== `string` || typeof pattern !== `string`) {
return false
}
const searchValue = caseInsensitive ? value.toLowerCase() : value
const searchPattern = caseInsensitive ? pattern.toLowerCase() : pattern
// Convert SQL LIKE pattern to regex
// First escape all regex special chars except % and _
let regexPattern = searchPattern.replace(/[.*+?^${}()|[\]\\]/g, `\\$&`)
// Then convert SQL wildcards to regex
regexPattern = regexPattern.replace(/%/g, `.*`) // % matches any sequence
regexPattern = regexPattern.replace(/_/g, `.`) // _ matches any single char
// 's' (dotAll flag) makes '.' match all characters including line terminations
const regex = new RegExp(`^${regexPattern}$`, 's')
return regex.test(searchValue)
}
PoC
import { createCollection, createLiveQueryCollection, like } from '@tanstack/db'
const collection = createCollection({
name: 'items',
schema: { name: 'string' },
sync: { type: 'none' },
})
const liveQuery = createLiveQueryCollection({
source: collection,
query: (q) => q.where(({ item }) => like(item.name, 'a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a')),
})
// Near-miss: long string that matches most of the pattern but fails at the end
// The 'b' at the end forces the engine into exponential backtracking
const nearMiss = 'a' + 'a'.repeat(50) + 'b'
const start = Date.now()
await liveQuery.refetch()
console.log(`Took ${Date.now() - start}ms`) // seconds to minutes
Why it's exploitable
like()/ilike()are part of the public query builder API, any app using TanStack/db can call them- The pattern string is accepted as
StringLike(barestring) with zero validation - Each
%becomes.*, creating N+1 overlapping unbounded quantifier segments - When tested against a near-miss string (long, matches most of the pattern but fails near the end), the regex engine tries all possible ways to distribute the input across the segments → exponential time
Remediation
Quick fix : limit wildcards in evaluateLike():
const MAX_WILDCARDS = 20
if ((pattern as string).match(/%/g)?.length > MAX_WILDCARDS) {
throw new Error('LIKE pattern contains too many wildcards')
}
Long-term : replace regex-based LIKE with a manual character-by-character matcher (e.g. KMP-style) for O(n*m) worst-case.
Submitting
Per TanStack's security advisory process, I'd like to submit a GHSA for this. Happy to provide a more detailed report or PoC video if needed.
- Vorherrschende Sprache
- TypeScript
- Sterne
- 4k
- Forks
- 277
- Ø Merge
- 1 T. 6 Std.
- Gemergte PRs (30 T.)
- 199
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Hat eine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus TanStack/db
-
Schwierigkeit 1/5 1-3 Stunden Anfängerfreundlichkeit 88/100
Maintainer antworten meist innerhalb von 1 Tag
-
OfflineExecutor.dispose() never settles pendingTransactionPromisesEvtl. vergeben @Claire-ovo hat das vor 4 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
TanStack/db#2254 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
Maintainer antworten meist innerhalb von 1 Tag
-
Two @tanstack/db tests time out under CPU load because a cold module import counts against the 5 s default timeoutEvtl. vergeben @jp-knj hat das vor 2 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 48/100
Maintainer antworten meist innerhalb von 1 Tag
Ähnliche Issues
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
Automattic/data-liberation-agent#1115 ·
Maintainer antworten meist innerhalb von 1 Tag
-
bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 88/100
Maintainer antworten meist innerhalb von 1 Tag
-
Enhance blog readabilityOffenCSS enhancement good first issue
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 70/100
pychess/pychess-variants#2448 ·
Maintainer antworten meist innerhalb von 1 Tag
-
[architect] Stale planning/scratch files at repo root (COMPONENT_SPLIT_SUMMARY.md etc.) describe already-completed workEvtl. vergeben @hivecommons-hive hat das heute übernommen. Offenagent/architect architecture help wanted stage/040-covered-by-pr tech-debt
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
kubestellar/console#24716 ·
Maintainer antworten meist innerhalb von 1 Tag
-
helm-knative-apply.sh fails with Helm 4Evtl. vergeben Ein verknüpfter Pull Request ist offen oder bereits gemergt. Offenarea: triage theme: undefined
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
jhipster/generator-jhipster#35895 ·
Maintainer antworten meist innerhalb von 1 Tag