Support wildcard/regex model redirects and honor them in provider selection#1
Support wildcard/regex model redirects and honor them in provider selection#1
Conversation
Signed-off-by: h7ml <h7ml@qq.com>
Signed-off-by: h7ml <h7ml@qq.com>
Signed-off-by: h7ml <h7ml@qq.com>
概览此次变更为模型重定向功能引入了多模式匹配系统,支持精确匹配、通配符和正则表达式三种模式类型。新增工具函数用于解析和验证重定向模式,并通过统一的查找逻辑替换了直接映射查询,同时将匹配细节传播到提供者链中。 变更
序列图sequenceDiagram
participant Client as 客户端请求
participant ProviderSelector as 提供者选择器
participant ModelRedirector as 模型重定向器
participant ProviderChain as 提供者链
Client->>ProviderSelector: 请求模型支持检查
ProviderSelector->>ModelRedirector: hasRedirect(modelRedirects, model)
ModelRedirector->>ModelRedirector: 逐一尝试精确/通配符/正则匹配
ModelRedirector-->>ProviderSelector: 返回匹配结果(true/false)
alt 找到重定向匹配
ProviderSelector->>ModelRedirector: findRedirectMatch(...)
ModelRedirector-->>ProviderSelector: 返回 {redirectedModel, matchedPattern, matchType}
ProviderSelector->>ProviderChain: 存储匹配细节到 ProviderChainItem
else 无匹配
ProviderSelector->>ProviderChain: 使用原始模型
end
ProviderChain-->>Client: 返回重定向结果
预估代码审查工作量🎯 3 (中等) | ⏱️ ~25 分钟 诗歌
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/app/v1/_lib/proxy/model-redirector.ts`:
- Around line 13-31: The parseRegexPattern function currently accepts
arbitrarily long regex bodies which can lead to catastrophic backtracking
(ReDoS) when later used (e.g., regexPattern.test(originalModel)); add a
defensively small maximum length check for the extracted body inside
parseRegexPattern (and reject patterns where body.length exceeds the limit) so
that dangerous or overly complex patterns are not compiled; keep the existing
try/catch for syntax errors and return null on length violation to preserve
current behavior.
🧹 Nitpick comments (2)
tests/unit/proxy/provider-selector-model-redirect.test.ts (1)
51-125: 测试覆盖建议:补充反向测试用例。当前两个新测试只验证了通配符匹配时供应商被选中的场景。建议补充以下用例以增强覆盖:
- 不匹配时应被过滤:请求的模型不匹配任何 redirect 模式时,
provider应为null。- 正则模式:除通配符外,测试
/^.../$/格式的 regex redirect 在 provider selection 中的行为。src/app/v1/_lib/proxy/model-redirector.ts (1)
46-76:findRedirectMatch中 RegExp 对象未缓存,每次调用重复编译。
hasRedirect在供应商选择循环中为每个 provider 调用,每次都会对所有 pattern 重新执行parseRegexPattern/buildWildcardRegex(构造new RegExp)。在典型规模下影响不大,但如果 provider 或 pattern 数量增长,性能可能成为瓶颈。可考虑在 provider 级别缓存已编译的正则(如使用
WeakMap<Provider, Map<string, RegExp>>),或在findRedirectMatch外层做一次预编译。
| function parseRegexPattern(pattern: string): RegExp | null { | ||
| if (!pattern.startsWith("/")) { | ||
| return null; | ||
| } | ||
| const lastSlashIndex = pattern.lastIndexOf("/"); | ||
| if (lastSlashIndex <= 0) { | ||
| return null; | ||
| } | ||
| const body = pattern.slice(1, lastSlashIndex); | ||
| const flags = pattern.slice(lastSlashIndex + 1); | ||
| if (!body) { | ||
| return null; | ||
| } | ||
| try { | ||
| return new RegExp(body, flags); | ||
| } catch { | ||
| return null; | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
JavaScript ReDoS protection libraries 2025
💡 Result:
JavaScript ReDoS protection libraries (practical options in/around 2025)
1) Switch to a non-backtracking regex engine (strongest runtime protection)
re2(node-re2): Native Node.js bindings to Google’s RE2; avoids catastrophic backtracking but does not support some JS regex features (notably lookarounds and backreferences). [1]re2-wasm: Runs RE2 via WebAssembly (useful when native addons are undesirable); same “safe engine” idea and similar feature tradeoffs. [2][3]
2) Detect risky regexes (CI/lint/test-time controls)
redos-detector: Library/CLI that scores how vulnerable a pattern is (browser/Node/Deno). [4]safe-regex2: Maintained fork ofsafe-regex; fast heuristic (“star height”) check—expects false positives/negatives (good as a cheap first pass). [5]safe-regex: Original package (widely used but older; same heuristic limitations). [6]vuln-regex-detector/davisjam/vuln-regex-detector: Heavier-weight detection aimed at finding real catastrophic-backtracking cases (includes project scanning workflow; testing can be expensive). [7][8]
3) Operational mitigations you should still do
Even with tooling, also apply input length limits and avoid building regexes directly from untrusted input. [9]
Notes on RE2 compatibility: if you plan to move patterns to RE2, many constructs are intentionally avoided/unsupported (e.g., lookarounds, backreferences). [1][10]
Sources:
[1] re2 (node-re2) package info on RE2 safety + unsupported features [2] re2-wasm npm [3] google/re2-wasm repo [4] redos-detector npm [5] safe-regex2 npm [6] safe-regex npm [7] vuln-regex-detector npm [8] davisjam/vuln-regex-detector GitHub [9] Bearer rule guidance on ReDoS mitigations [10] OWASP CRS note on non-backtracking/RE2-compatible regex constraints
🌐 Web query:
regular expression denial of service prevention techniques Node.js
💡 Result:
ReDoS prevention techniques in Node.js (practical checklist)
-
Avoid “evil” patterns in the first place
- Biggest risks: nested quantifiers and overlapping alternation (classic catastrophic backtracking). OWASP explicitly warns to “stay away from evil regexes” in Node.js. [1]
-
Constrain what the regex has to process
- Hard cap input length (and ideally also min/max lengths in the regex like
{1,25}) as part of input validation guidance. [2] - Prefer allowlists (tight character classes) over broad patterns like
.*/.+when possible.
- Hard cap input length (and ideally also min/max lengths in the regex like
-
Use a linear-time regex engine for untrusted regexes (or high-risk matches)
- If users can supply patterns (or you must run complex patterns on untrusted data), use RE2 via the
re2(node-re2) package; it avoids catastrophic backtracking by using a non-backtracking engine (with feature tradeoffs like no lookaheads/backreferences). [3]
- If users can supply patterns (or you must run complex patterns on untrusted data), use RE2 via the
-
Detect risky regexes in CI / code review
- Add automated checks like
safe-regex2to flag potentially catastrophic patterns (useful, but it can have false positives/negatives). [4] - OWASP notes there are tools to test whether regexes are vulnerable to ReDoS. [1]
- Add automated checks like
-
Put regex work behind a “circuit breaker”
- Node doesn’t have a built-in per-regex timeout, so for worst-case safety run high-risk matches in a Worker thread / child process and enforce a deadline (terminate the worker/process if it exceeds).
- If you control Node/V8 startup flags, V8 has an experimental non-backtracking fallback after “excessive backtracks” (runtime hardening option; pattern/flag limitations apply). [5]
Sources: OWASP Node.js Security Cheat Sheet [1], OWASP Input Validation Cheat Sheet [2], re2/node-re2 docs [3], safe-regex2 docs [4], V8 non-backtracking RegExp engine blog [5].
🏁 Script executed:
# First, let's examine the actual file to understand the context better
cat -n src/app/v1/_lib/proxy/model-redirector.ts | head -100Repository: dext7r/claude-code-hub
Length of output: 3456
🏁 Script executed:
# Let's check how modelRedirects is defined and where parseRegexPattern is used
rg "modelRedirects" src/app/v1/_lib/proxy/model-redirector.ts -A 2 -B 2Repository: dext7r/claude-code-hub
Length of output: 1478
🏁 Script executed:
# Check the provider configuration to understand the source of modelRedirects data
rg "modelRedirects" src/ -l | head -20Repository: dext7r/claude-code-hub
Length of output: 764
🏁 Script executed:
# Let's check how the modelRedirects are populated to confirm they're admin-configured
rg "provider\.modelRedirects\s*=" src/ -A 3 | head -40Repository: dext7r/claude-code-hub
Length of output: 48
🏁 Script executed:
# Check the types to understand the Provider structure and source of modelRedirects
cat -n src/types/provider.ts | grep -A 5 -B 5 "modelRedirects"Repository: dext7r/claude-code-hub
Length of output: 833
ReDoS 风险:管理员配置的正则模式可导致事件循环阻塞。
虽然 modelRedirects 来自供应商配置而非终端用户 HTTP 请求(降低了攻击面),但恶意或失误的正则表达式(如 /(a+)+$/)仍可在 regexPattern.test(originalModel) 执行时触发灾难性回溯,阻塞事件循环。现有的 try-catch 仅捕获语法错误,无法阻止计算复杂度攻击。
建议在 parseRegexPattern 中添加长度限制,这是业界公认的防护措施:
修复方案:添加正则 body 长度上限
function parseRegexPattern(pattern: string): RegExp | null {
if (!pattern.startsWith("/")) {
return null;
}
const lastSlashIndex = pattern.lastIndexOf("/");
if (lastSlashIndex <= 0) {
return null;
}
const body = pattern.slice(1, lastSlashIndex);
const flags = pattern.slice(lastSlashIndex + 1);
- if (!body) {
+ if (!body || body.length > 200) {
return null;
}
try {
return new RegExp(body, flags);
} catch {
return null;
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function parseRegexPattern(pattern: string): RegExp | null { | |
| if (!pattern.startsWith("/")) { | |
| return null; | |
| } | |
| const lastSlashIndex = pattern.lastIndexOf("/"); | |
| if (lastSlashIndex <= 0) { | |
| return null; | |
| } | |
| const body = pattern.slice(1, lastSlashIndex); | |
| const flags = pattern.slice(lastSlashIndex + 1); | |
| if (!body) { | |
| return null; | |
| } | |
| try { | |
| return new RegExp(body, flags); | |
| } catch { | |
| return null; | |
| } | |
| } | |
| function parseRegexPattern(pattern: string): RegExp | null { | |
| if (!pattern.startsWith("/")) { | |
| return null; | |
| } | |
| const lastSlashIndex = pattern.lastIndexOf("/"); | |
| if (lastSlashIndex <= 0) { | |
| return null; | |
| } | |
| const body = pattern.slice(1, lastSlashIndex); | |
| const flags = pattern.slice(lastSlashIndex + 1); | |
| if (!body || body.length > 200) { | |
| return null; | |
| } | |
| try { | |
| return new RegExp(body, flags); | |
| } catch { | |
| return null; | |
| } | |
| } |
🧰 Tools
🪛 ast-grep (0.40.5)
[warning] 26-26: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(body, flags)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
🤖 Prompt for AI Agents
In `@src/app/v1/_lib/proxy/model-redirector.ts` around lines 13 - 31, The
parseRegexPattern function currently accepts arbitrarily long regex bodies which
can lead to catastrophic backtracking (ReDoS) when later used (e.g.,
regexPattern.test(originalModel)); add a defensively small maximum length check
for the extracted body inside parseRegexPattern (and reject patterns where
body.length exceeds the limit) so that dangerous or overly complex patterns are
not compiled; keep the existing try/catch for syntax errors and return null on
length violation to preserve current behavior.
Motivation
gpt-*, or regex/^...$/) so incoming requests can be mapped to an upstream model even when the requested name is not an exact whitelist entry.Description
src/app/v1/_lib/proxy/model-redirector.tswithparseRegexPattern,buildWildcardRegex, andfindRedirectMatchto supportexact,wildcard, andregexmatches, and wired them intoModelRedirector.apply,ModelRedirector.getRedirectedModel, andModelRedirector.hasRedirect.ProviderChainItem.modelRedirectinsrc/types/message.tswithmatchedPatternandmatchTypefields.src/app/v1/_lib/proxy/provider-selector.tsto consider redirect patterns when evaluatingallowedModelsso Claude providers with matching redirect patterns can be selected even ifallowedModelsexcludes the requested model.tests/unit/proxy/model-redirector-patterns.test.tsand extendedtests/unit/proxy/provider-selector-model-redirect.test.tsto include wildcard/redirect scenarios.Testing
tests/unit/proxy/but running the project automation failed in this environment because runtime tools are not installed:bun run buildfailed (nextnot found),bun run lintandbun run lint:fixfailed (biomenot found),bun run typecheckfailed (tsgonot found), andbun run testfailed (vitestnot found).tests/unit/proxy/model-redirector-patterns.test.tsand updatedtests/unit/proxy/provider-selector-model-redirect.test.ts).Codex Task
Summary by CodeRabbit
版本发布说明
新功能
测试