Skip to content

chore: integrate official Sub2API v0.2.14 security fixes - #258

Merged
HTExplicit merged 105 commits into
mainfrom
sync/upstream-0.2.14
Oct 7, 2026
Merged

HTExplicit merged 105 commits into
mainfrom
sync/upstream-0.2.14

Conversation

@HTExplicit

Copy link
Copy Markdown
Owner

Integrate official Sub2API v0.2.14 (0363b8cdba8cec3e2ba4b2dbd49c4481143fa55d) into the current codexrip downstream. The release hardens fresh administrator setup and EasyPay callbacks and restores API-key model discovery in generated remote Codex configurations.

  • Record the already integrated official v0.2.13 ancestry without changing its code tree, then use a normal upstream merge.
  • Keep the patched SheetJS CDN 0.20.3 dependency and existing downstream security constraints; adopt Vue ^3.5.43 and the official DOMPurify/source-map-js constraints. Regenerate and install the final lockfile frozen; do not renew XLSX exceptions.
  • Preserve all 355 existing SQL migrations, migration 274's checksum, Ent schemas, reasoning recovery, account/model/capacity contracts, system prompts, UI styles and the single-operation production deploy path. No new database migration.
  • Resolve only audit-exception, package and lockfile conflicts. The refreshed risk snapshot requires review (11 overlap / 10 critical paths), and independent read-only review of the frozen tree found no actionable defects.

Validation: selected new setup/bootstrap and EasyPay/return-URL cases passed. Eleven mounted real-modal Codex config scenarios passed, covering all four remote/file generators and the 1 MiB fallback. Frozen installation resolved Vue 3.5.43, DOMPurify 3.4.14 and XLSX 0.20.3; the normal production audit policy passed with zero high/critical findings. Raw dev-inclusive audit findings are not claimed clean. Backend security files match the fixed upstream tag; unmodified downstream subsystems are preserved by blob comparison. Normal required CI still gates admission. No live model/payment calls, business backups or production configuration changes.

Production remains on v0.2.13-codexrip.13 until the new immutable v0.2.14-codexrip.1 release is built and deployed through the existing protected workflow.

aofee and others added 30 commits September 20, 2026 20:20
分组开启 claude_code_only 并配置降级分组时,/v1/messages 会在选号入口的
checkClaudeCodeRestriction 中把非 Claude Code 请求解析到降级分组;但
GatewayHandler.ChatCompletions / Responses 在 handler 层只要分组开了
claude_code_only 就直接返回 403,不看降级分组,请求到不了调度层:只会发
Chat Completions / Responses 的第三方客户端拿这类分组的 Key 一律 403。

- handler 层提前拒绝只在未配置降级分组时生效,拒绝的状态码与文案不变
- 配置了降级分组时请求继续,由 SelectAccountWithLoadAwareness 解析到降级分组
  选号,再经已有的 Chat Completions / Responses ⇄ Anthropic Messages 转换转发;
  service 层无改动
- 与 /v1/messages 的降级语义一致:选号与渠道限制预检按降级分组,计费与用量
  记录仍按 API Key 所属分组

新增 handler 单测覆盖两个入口在有/无降级分组时的行为。
Replace the static priority number in the accounts table with a compact
stepper: hover reveals -/+ buttons, clicking the value allows typing
(Enter to save, Esc to cancel, arrow keys to nudge). Rapid clicks are
debounced into a single priority-only PUT, failures revert the value and
surface a toast, and the row is patched in place without a full reload.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
disabled:opacity-30 overrode opacity-0, so the decrement button stayed
faintly visible on every row already at the minimum. Style disabled
buttons via text colour instead, and raise idle icon contrast.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
POST /api/v1/payment/public/orders/verify is unauthenticated and still used
by PaymentResultView as a fallback, so keep it but cap it at 20 req/min per
client IP (fail-open on Redis errors) to make out_trade_no enumeration
impractical without affecting users mid-payment.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ient

The antigravity Gemini forward path returned the raw upstream Google error
body to end users, which can contain consumer project numbers, GCP project
IDs and service account emails. Return a Gemini-style error body with only
code/status and a scrubbed message; raw body stays in ops logging.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…okens

- Verification code attempts (register + notify email) are now reserved via
  an atomic Redis INCR (Lua) before comparing, so concurrent wrong guesses
  cannot exceed the 5-attempt cap.
- Password reset tokens are stored as SHA-256 hashes and consumed with an
  atomic Lua compare-and-delete, so a token can only be used once even under
  concurrent requests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Balance-mode admission only checked cached balance > threshold, so N
concurrent expensive requests could all pass and overdraw the user.
Add a Redis in-flight reservation: at admission estimate a conservative
per-request cost (input estimate + output price x max_tokens, times rate
multiplier) and atomically require cached_balance - inflight >= estimate
(first in-flight request always admitted). Reservations are released via
defer on every path and expire by TTL. Fails open on estimation / Redis
errors. Configurable via billing.inflight_reservation (enabled by default).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…timate like billing; wire remaining endpoints

Address gaps found in adversarial verification of the in-flight balance
reservation:

- Early release: the reservation is now a ref-counted handle carried on the
  request context. Billing tasks submitted via submit*UsageRecordTask take a
  ref and return it only after RecordUsage has run; with reservation enabled
  the balance cache is deducted synchronously inside the billing task, so the
  reservation is released only after admission can see the deduction. Dropped
  tasks return their ref immediately. The reservation is renewed every ttl/3
  while the handler runs; after the handler returns it is no longer renewed,
  so the post-handler hold is bounded by one TTL.
- Estimate: use the same billing model (channel mapping + BillingModelSource,
  max over requested/mapped when ambiguous) and ModelPricingResolver (group
  ModelPricing incl. wildcards, channel per_request/image/video/token
  overrides), default/group/user rate + peak multiplier, plus image, video,
  audio and search surcharge kinds. Unpriced requests fail open with a
  throttled log; new billing.inflight_reservation.fail_closed_on_unpriced
  (default false) rejects them instead.
- Wire images, embeddings, web/x search, alpha search, grok media generation,
  grok realtime/voice, OpenAI-platform /v1/messages and ResponsesWebSocket
  (session-level reservation with renewal).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…don't renew expired reservations

- Inflight estimate now mirrors billableModelWithFallback: when the primary
  billing model has no price, fall back to the channel-mapped model (also for
  billing_model_source=requested) and to account-level mapped models (max over
  schedulable accounts in the group, cached 30s).
- Composite groups also consider concrete account-mapped models (max) so the
  alias' family fuzzy price cannot underestimate.
- Renew Lua refuses (and purges) members whose score <= now.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…y when unpriced

- only consult account mappings after primary/channel candidates fail to price (or composite)
- source mappings from the scheduler snapshot (same pool as account selection), no direct DB query and no per-model cache
- ungrouped API keys use the scheduler's ungrouped pool
- no negative caching: new mappings take effect on the next request

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Wei-Shaw and others added 26 commits October 2, 2026 14:31
…der-verify-hardening

fix(payment): 为匿名订单查询接口 /payment/public/orders/verify 增加 IP 限流
…group-sort

feat(keys): 支持按分组名称排序 API 密钥
…ty-sanitize-upstream-error

fix(antigravity): 返回客户端前脱敏上游错误体,避免泄露账号池身份
…e-token-atomic

fix(email): 验证码尝试次数原子化 + 重置密码 token 哈希存储且原子单次消费
…ror-codes-warning-text

fix(frontend): correct custom error code warning and upgrade Axios
…priority-quick-adjust

feat(admin): inline quick-adjust stepper for account priority
The create form shows the upstream billing auto-probe toggle for every
API-key platform and enables it by default. TypeSafe was added as an
API-key platform but not to IsUpstreamBillingProbeIdentity, so creating a
TypeSafe account with the default form state fails with
400 UPSTREAM_BILLING_PROBE_ACCOUNT_INVALID ("account is not an API key
account").

TypeSafe accounts store credentials.api_key/base_url like every other
API-key platform, which is all the probe reads. Add TypeSafe to the probe
identity set, and add typesafe.ai to the official API domains so accounts
on the default https://api.typesafe.ai base URL record "unsupported"
without sending the key to a path that cannot exist, matching the other
official providers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs: add security policy with private vulnerability reporting
… completes

When an API key with quota or rate limits was deleted while a request was
still in flight, the key counter update matched no rows and returned
ErrAPIKeyNotFound, rolling back the whole billing transaction including the
balance/subscription charge. Skip the key-scoped counters in that case and
keep settling the user and account side as usual.
…ted-key

fix(billing): settle usage when the API key is deleted before billing completes
…am-billing-probe

fix(billing): allow upstream billing probe for TypeSafe API-key accounts
An order-creation signature (visible to the payer in popup submit.php
URLs) could be replayed as a payment-success notification, with no
merchant key required. Two compounding defects:

- CanonicalizeReturnURL kept client-supplied query parameters, so a
  return_url ending in '&trade_status=TRADE_SUCCESS' entered the signed
  order string verbatim;
- the sign base string concatenates values unescaped, so a callback that
  decodes return_url only up to the smuggled pair re-sorts to a
  byte-identical sign base and passes verification.

Fixes:

- CanonicalizeReturnURL now drops client query parameters entirely; the
  server builds its own signed set and the client query has no
  legitimate use;
- VerifyNotification rejects any parameter outside the genuine async
  notify set (pid/trade_no/out_trade_no/type/name/money/trade_status/
  param/sign/sign_type), failing closed against the whole smuggling
  class regardless of the injection point.

Regression tests cover the PoC payload, full order-URL replay, genuine
callback acceptance, unknown-parameter rejection (including empty
values), and the return_url smuggling strip. Genuinely paid orders that
an exotic upstream variant might reject are still recovered through the
existing upstream QueryOrder reconcile path.
…alog-discovery

fix: enable API-key discovery for remote Codex catalogs
…forgery

fix(payment): 修复易支付回调签名复用伪造入账漏洞 (fixes #7881)
…ls (fixes Wei-Shaw#7850)

Fresh Docker installs created the admin as admin@sub2api.local and accepted
any ADMIN_PASSWORD (e.g. "123456"), making them easy brute-force targets.

- Generate a random admin-<12 hex>@sub2api.local login email when
  ADMIN_EMAIL is empty; drop the fixed default from .env.example and the
  compose files, and have docker-deploy.sh write a random ADMIN_EMAIL.
- Validate user-supplied ADMIN_PASSWORD (8-72 bytes) and ADMIN_EMAIL on the
  auto-setup path, only when an admin is actually about to be created, so
  existing deployments are never blocked at startup.
- Align validateEmail with the login endpoint's email binding so setup can no
  longer create an admin that can never log in (e.g. "a@b", "Name <a@b.com>").
- Cap validatePassword at bcrypt's 72-byte limit; the CLI reuses it and now
  defaults to a random admin email instead of admin@example.com.
- Update READMEs/deploy docs to stop suggesting guessable credentials.
…exceptions)

- Bump vue to ^3.5.43 so @vue/server-renderer is >= 3.5.42
  (GHSA-g2v6-rqmx-r4w6).
- Override source-map-js to >= 1.2.2 (GHSA-68fv-2mgg-jv7q).
- Renew the expired xlsx exceptions until 2027-01-06: xlsx has no patched
  release on npm and is only used for XLSX.write export in the admin usage
  view; both advisories require parsing a crafted file and no read path exists.

Lockfile regenerated with pnpm 9 to match CI.
…ootstrap-hardening

fix(setup): stop shipping guessable admin credentials on fresh installs (fixes Wei-Shaw#7850)
# Conflicts:
#	.github/audit-exceptions.yml
#	frontend/package.json
#	frontend/pnpm-lock.yaml
@HTExplicit HTExplicit added the upstream-reviewed Human upstream overlap review completed label Oct 7, 2026
@HTExplicit
HTExplicit enabled auto-merge October 7, 2026 10:45
@HTExplicit
HTExplicit merged commit 0fd6d38 into main Oct 7, 2026
21 of 22 checks passed
@HTExplicit
HTExplicit deleted the sync/upstream-0.2.14 branch October 7, 2026 10:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

upstream-reviewed Human upstream overlap review completed

Projects

None yet

Development

Successfully merging this pull request may close these issues.