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
Block IPv4-mapped IPv6 private hosts in provider base URL validation.
Classify provider HTTP 403 as forbidden while keeping 401 as auth_failed.
Preserve existing versioned provider paths such as /v2 and clean up pending API-mode user messages when a session is killed before the provider response returns.
Root Cause
The provider runtime only checked plain IPv4 and a narrow set of IPv6 private patterns, so ::ffff:* addresses could bypass the private-host block.
Provider 403 responses were grouped with 401 auth failures, masking permission/model-tier failures as invalid keys.
API-mode session turns inserted the user message before the provider call and did not roll that message back if the session was killed while awaiting the provider.
Validation
git diff --check
bun run test (164/164 passed on the hotfix branch)
[should-fix] Emit/DB divergence on session kill — api-session-runtime.ts:97–112: The user-message event is emitted unconditionally at line 97, before the provider call. When the session is killed and the DB row is deleted (lines 110–112), no compensating event is emitted. A client watching the stream will have received the { type: "message", role: "user" } event; on reconnect it loads from DB and sees nothing. Whether this matters depends on whether killed-session streams are torn down before the check fires, but the silent divergence is worth addressing — either defer the emit until after the kill-check, or emit a { type: "revoke_message" } tombstone event. Fix this →
[nit] parseIpv4MappedIpv6 relies on URL constructor normalization — api-provider-runtime.ts:80: The two prefix strings ("::ffff:", "0:0:0:0:0:ffff:") only cover post-normalization forms. This is safe because all callers pass url.hostname which the URL constructor already normalizes, but the function's contract isn't expressed anywhere. A brief inline comment (e.g. // expects post-URL-parse normalized hostname) would make the dependency explicit and prevent misuse if the function is called elsewhere.
[nit] Duplicated classifyProviderFailure — both api-provider-runtime.ts:579 and api-provider-models.ts:262 contain identical copies of this function and were both updated in sync here. This PR is a good opportunity to extract to a shared helper to eliminate future drift risk.
[nit] Missing test for hex-form IPv4-mapped IPv6 — ::ffff:c0a8:101 (hex for 192.168.1.1) is a valid input that exercises the high/low word-split path in parseIpv4MappedIpv6 but has no test. The logic is correct, but coverage is incomplete.
Assessment
The three core fixes are all correct:
IPv4-mapped IPv6 blocking: parseIpv4MappedIpv6 correctly handles both dotted-decimal and hex-word forms. The parseIpv6FirstGroup rewrite replacing the regex on the raw string is strictly better — the bitmask approach ((firstGroup & 0xfe00) === 0xfc00 for fc00::/7, (firstGroup & 0xffc0) === 0xfe80 for fe80::/10) is the canonical way to test these ranges and avoids false positives from the old regex on edge addresses like fcc0::, fe90::, etc.
403 → forbidden: The split is semantically correct. 401 = invalid/missing credential; 403 = valid credential but insufficient permission or model-tier restriction. Masking them into the same kind was lossy.
User-message rollback on session kill: The lastInsertRowid-scoped DELETE is the right approach — it avoids a TOCTOU where a second message with the same content could be incorrectly deleted. The existing test update confirms the expected new behavior.
Versioned path regex: /\/v\d+(?:beta)?$/ correctly covers /v1, /v2, /v1beta (Google), etc. and is a clear improvement over the prior endsWith("/v1") check.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
forbiddenwhile keeping 401 asauth_failed./v2and clean up pending API-mode user messages when a session is killed before the provider response returns.Root Cause
::ffff:*addresses could bypass the private-host block.Validation
git diff --checkbun run test(164/164 passed on the hotfix branch)bun run typecheckbun run build