Skip to content

fix(gateway): clear auto-fallback model override on session reset#63155

Merged
frankekn merged 5 commits into
openclaw:mainfrom
frankekn:fix/clear-auto-fallback-override-on-reset
Apr 8, 2026
Merged

fix(gateway): clear auto-fallback model override on session reset#63155
frankekn merged 5 commits into
openclaw:mainfrom
frankekn:fix/clear-auto-fallback-override-on-reset

Conversation

@frankekn

@frankekn frankekn commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fix sticky fallback model override surviving /reset and /new commands
  • Only preserve providerOverride/modelOverride/authProfileOverride across session reset when authProfileOverrideSource === "user" (explicit /model command)
  • System-driven overrides (authProfileOverrideSource: "auto", from fallback rotation) are now dropped on reset so the session picks up the current config default

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: commit cb0a752 ("fix: preserve reset session behavior config", v2026.3.28) added providerOverride, modelOverride, authProfileOverride, authProfileOverrideSource, and authProfileOverrideCompactionCount to the fields unconditionally copied during session reset in performGatewaySessionReset(). This was correct for user-driven /model selections (authProfileOverrideSource: "user"), but it also preserved fallback-driven overrides (authProfileOverrideSource: "auto") written by persistFallbackCandidateSelection().
  • Precedence issue: the session store override takes precedence over the agent config default provider. When a fallback override survives reset, the new session uses the fallback provider instead of the configured primary, even if the user has since changed the agent config.
  • Repro sequence: (1) primary provider fails, fallback to secondary succeeds, (2) persistFallbackCandidateSelection() writes providerOverride with authProfileOverrideSource: "auto", (3) user updates agent config to a different primary provider, (4) /reset or /new copies the stale fallback override to the new session, (5) new session ignores the config change and keeps using the fallback provider.
  • Fix: make the override copy conditional on authProfileOverrideSource === "user" so only explicit user selections survive reset.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Scenario the test should lock in: session reset with authProfileOverrideSource: "auto" should not carry forward override fields; session reset with authProfileOverrideSource: "user" should preserve them.
  • If no new test is added, why not: the fix is a minimal conditional guard on existing field copying; adding a test would require extensive mocking of the session store and config infrastructure. The behavior is straightforward to verify by inspection.

User-visible / Behavior Changes

After a fallback rotation, /reset or /new now returns the session to the configured default model/provider instead of keeping the fallback override. Explicit /model selections continue to be preserved across reset as before.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: XS maintainer Maintainer-authored PR labels Apr 8, 2026
@greptile-apps

greptile-apps Bot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a regression introduced in cb0a752 where providerOverride, modelOverride, authProfileOverride, authProfileOverrideSource, and authProfileOverrideCompactionCount were unconditionally copied in performGatewaySessionReset(). The fix makes the copy conditional on authProfileOverrideSource === "user", so only explicit /model selections survive /reset or /new while system-driven fallback overrides are correctly discarded.

Confidence Score: 5/5

Safe to merge — targeted one-line conditional guard with no unintended side effects and existing integration test coverage for the preserved path.

The fix is minimal and correct. The authProfileOverrideSource type is a closed 'auto' | 'user' union, so the condition exhaustively handles every case. Existing tests in server.sessions.gateway-server-sessions-a.test.ts already cover the 'user' path. No P0 or P1 findings.

No files require special attention.

Vulnerabilities

No security concerns identified.

Reviews (1): Last reviewed commit: "fix(gateway): clear auto-fallback model ..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2a054e197a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/gateway/session-reset-service.ts Outdated
Comment on lines +547 to +549
...(currentEntry?.authProfileOverrideSource === "user"
? {
providerOverride: currentEntry?.providerOverride,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve explicit model overrides without auth profile source

The new guard only carries providerOverride/modelOverride when authProfileOverrideSource === "user", but explicit user model picks often do not set that field. applyModelOverrideToSessionEntry() clears authProfileOverrideSource whenever no profile override is provided, while still persisting providerOverride and modelOverride (for example from /model or sessions.patch paths), so those user-selected overrides now get dropped on /reset//new and the session incorrectly reverts to defaults.

Useful? React with 👍 / 👎.

@frankekn

frankekn commented Apr 8, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

1 similar comment
@frankekn

frankekn commented Apr 8, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fd2e06b257

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/gateway/session-reset-service.ts Outdated
Comment on lines +131 to +135
const explicitSelection = fallbackPinnedSelection ?? currentSelection;
if (explicitSelection && !sameProviderModelRef(explicitSelection, defaultRef)) {
preserved.providerOverride = explicitSelection.provider;
preserved.modelOverride = explicitSelection.model;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid preserving stale fallback-selected model on reset

This logic can still pin a stale model after config changes: when currentSelection matches fallbackNoticeActiveModel, it rewrites to fallbackNoticeSelectedModel and preserves it if it differs from the current default. In the common sequence “default A falls back to B, user changes config default to C, then /reset”, this keeps an override to old A instead of returning to C, so reset still ignores updated agent config.

Useful? React with 👍 / 👎.

@frankekn

frankekn commented Apr 8, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25cfe71aec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/gateway/session-reset-service.ts Outdated
}

const preserved: Partial<ResetPreservedSelectionState> = {};
if (entry.modelOverrideSource === "user" && entry.modelOverride) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve legacy user model overrides during reset

resolveResetPreservedSelection now keeps model overrides only when modelOverrideSource === "user", but this new field did not exist in previously persisted sessions, so existing user-selected overrides (modelOverride/providerOverride with no source) are treated like auto fallback and dropped on /reset//new. This creates an upgrade regression for users who had explicit model selections before this commit, because their next reset silently reverts to config defaults; please treat missing source as legacy-user (or backfill source before reset) when modelOverride is present.

Useful? React with 👍 / 👎.

@frankekn

frankekn commented Apr 8, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

Codex Review: Didn't find any major issues. Swish!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@frankekn
frankekn force-pushed the fix/clear-auto-fallback-override-on-reset branch from e0c278b to 7560566 Compare April 8, 2026 16:30
termtek and others added 5 commits April 9, 2026 00:30
When `persistFallbackCandidateSelection()` writes a fallback provider
override with `authProfileOverrideSource: "auto"`, the override was
incorrectly preserved across `/reset` and `/new` commands. This caused
sessions to keep using the fallback provider even after the user changed
the agent config primary provider, because the session store override
takes precedence over the config default.

Now the override fields (`providerOverride`, `modelOverride`,
`authProfileOverride`, `authProfileOverrideSource`,
`authProfileOverrideCompactionCount`) are only carried forward when
`authProfileOverrideSource === "user"` (i.e. explicit `/model` command).
System-driven overrides are dropped on reset so the session picks up the
current config default.

Introduced in cb0a752 ("fix: preserve reset session behavior config")
@frankekn
frankekn force-pushed the fix/clear-auto-fallback-override-on-reset branch from 7560566 to 69610fa Compare April 8, 2026 16:30
@frankekn
frankekn merged commit 5d46e4d into openclaw:main Apr 8, 2026
9 checks passed
@aisle-research-bot

aisle-research-bot Bot commented Apr 8, 2026

Copy link
Copy Markdown

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🟠 High Policy bypass: legacy sessions without modelOverrideSource are treated as user model overrides during sessions.reset
1. 🟠 Policy bypass: legacy sessions without modelOverrideSource are treated as user model overrides during sessions.reset
Property Value
Severity High
CWE CWE-285
Location src/gateway/session-reset-service.ts:83-93

Description

sessions.reset backfills modelOverrideSource: "user" whenever modelOverrideSource is absent but modelOverride is present.

This is dangerous because older versions could persist providerOverride/modelOverride for non-user reasons (notably auto-fallback pinning). After this change:

  • Any legacy session entry with modelOverride set and no modelOverrideSource will be treated as an explicit user choice.
  • That selection is preserved across /sessions.reset and rewritten to disk as modelOverrideSource: "user".
  • The preserved override then flows into resolveSessionModelRef(...), which does not validate the override against the model allowlist (resolveAllowedModelRef is only applied on sessions.patch), enabling a stored/legacy override to keep using a model/provider that current policy would reject.

Impact depends on deployment, but in environments where model selection is restricted (allowlist, provider restrictions, cost controls), this can become a model/provider policy bypass.

Vulnerable code:

const preserveLegacyUserModelOverride =
  entry.modelOverrideSource === "user" ||
  (entry.modelOverrideSource === undefined && Boolean(entry.modelOverride));
if (preserveLegacyUserModelOverride && entry.modelOverride) {
  preserved.providerOverride = entry.providerOverride;
  preserved.modelOverride = entry.modelOverride;
  preserved.modelOverrideSource = "user";
}

Recommendation

Do not assume modelOverrideSource === undefined implies a user override.

Safer options:

  1. Only preserve overrides explicitly marked as user:
const preserveUserModelOverride = entry.modelOverrideSource === "user";
  1. If you must migrate legacy sessions, do it with an explicit heuristic that can distinguish auto-fallback from user choice (e.g., presence of fallback notice fields, or a separate legacy migration version):
const looksLikeAutoFallback = Boolean(
  entry.fallbackNoticeActiveModel ||
  entry.fallbackNoticeSelectedModel ||
  entry.fallbackNoticeReason
);
const preserveLegacy = entry.modelOverrideSource === undefined && entry.modelOverride && !looksLikeAutoFallback;

if ((entry.modelOverrideSource === "user" || preserveLegacy) && entry.modelOverride) {
  preserved.providerOverride = entry.providerOverride;
  preserved.modelOverride = entry.modelOverride;
  preserved.modelOverrideSource = "user";
}
  1. Additionally, re-validate any preserved override against the same allowlist/policy used by sessions.patch before persisting it (e.g., call resolveAllowedModelRef with the model catalog during reset and drop/clear the override if not allowed).

Analyzed PR: #63155 at commit 69610fa

Last updated on: 2026-04-08T16:38:00Z

@frankekn frankekn self-assigned this Apr 8, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 69610faf2f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

preserved.modelOverrideSource = "user";
}

if (entry.authProfileOverrideSource === "user" && entry.authProfileOverride) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve legacy auth profile overrides on reset

The new reset guard only keeps authProfileOverride when authProfileOverrideSource === "user", but older persisted sessions can have an explicit user profile override without the source field. In that upgrade scenario, /reset//new now drops the auth profile while still keeping the model override, which can silently switch credentials/account selection after reset. Please treat a missing source as legacy-user when authProfileOverride is present (or backfill it before reset), similar to how legacy modelOverrideSource is handled.

Useful? React with 👍 / 👎.

eleqtrizit pushed a commit that referenced this pull request Apr 8, 2026
…3155)

* fix(gateway): clear auto-fallback model override on session reset

When `persistFallbackCandidateSelection()` writes a fallback provider
override with `authProfileOverrideSource: "auto"`, the override was
incorrectly preserved across `/reset` and `/new` commands. This caused
sessions to keep using the fallback provider even after the user changed
the agent config primary provider, because the session store override
takes precedence over the config default.

Now the override fields (`providerOverride`, `modelOverride`,
`authProfileOverride`, `authProfileOverrideSource`,
`authProfileOverrideCompactionCount`) are only carried forward when
`authProfileOverrideSource === "user"` (i.e. explicit `/model` command).
System-driven overrides are dropped on reset so the session picks up the
current config default.

Introduced in cb0a752 ("fix: preserve reset session behavior config")

* fix(gateway): preserve explicit reset model selection

* fix(gateway): track reset model override source

* fix(gateway): preserve legacy reset model overrides

* docs(changelog): add session reset merge note

---------

Co-authored-by: termtek <[email protected]>
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
…enclaw#63155)

* fix(gateway): clear auto-fallback model override on session reset

When `persistFallbackCandidateSelection()` writes a fallback provider
override with `authProfileOverrideSource: "auto"`, the override was
incorrectly preserved across `/reset` and `/new` commands. This caused
sessions to keep using the fallback provider even after the user changed
the agent config primary provider, because the session store override
takes precedence over the config default.

Now the override fields (`providerOverride`, `modelOverride`,
`authProfileOverride`, `authProfileOverrideSource`,
`authProfileOverrideCompactionCount`) are only carried forward when
`authProfileOverrideSource === "user"` (i.e. explicit `/model` command).
System-driven overrides are dropped on reset so the session picks up the
current config default.

Introduced in d38868a ("fix: preserve reset session behavior config")

* fix(gateway): preserve explicit reset model selection

* fix(gateway): track reset model override source

* fix(gateway): preserve legacy reset model overrides

* docs(changelog): add session reset merge note

---------

Co-authored-by: termtek <[email protected]>
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
…enclaw#63155)

* fix(gateway): clear auto-fallback model override on session reset

When `persistFallbackCandidateSelection()` writes a fallback provider
override with `authProfileOverrideSource: "auto"`, the override was
incorrectly preserved across `/reset` and `/new` commands. This caused
sessions to keep using the fallback provider even after the user changed
the agent config primary provider, because the session store override
takes precedence over the config default.

Now the override fields (`providerOverride`, `modelOverride`,
`authProfileOverride`, `authProfileOverrideSource`,
`authProfileOverrideCompactionCount`) are only carried forward when
`authProfileOverrideSource === "user"` (i.e. explicit `/model` command).
System-driven overrides are dropped on reset so the session picks up the
current config default.

Introduced in 2ec7272 ("fix: preserve reset session behavior config")

* fix(gateway): preserve explicit reset model selection

* fix(gateway): track reset model override source

* fix(gateway): preserve legacy reset model overrides

* docs(changelog): add session reset merge note

---------

Co-authored-by: termtek <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
…enclaw#63155)

* fix(gateway): clear auto-fallback model override on session reset

When `persistFallbackCandidateSelection()` writes a fallback provider
override with `authProfileOverrideSource: "auto"`, the override was
incorrectly preserved across `/reset` and `/new` commands. This caused
sessions to keep using the fallback provider even after the user changed
the agent config primary provider, because the session store override
takes precedence over the config default.

Now the override fields (`providerOverride`, `modelOverride`,
`authProfileOverride`, `authProfileOverrideSource`,
`authProfileOverrideCompactionCount`) are only carried forward when
`authProfileOverrideSource === "user"` (i.e. explicit `/model` command).
System-driven overrides are dropped on reset so the session picks up the
current config default.

Introduced in e848007 ("fix: preserve reset session behavior config")

* fix(gateway): preserve explicit reset model selection

* fix(gateway): track reset model override source

* fix(gateway): preserve legacy reset model overrides

* docs(changelog): add session reset merge note

---------

Co-authored-by: termtek <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
…enclaw#63155)

* fix(gateway): clear auto-fallback model override on session reset

When `persistFallbackCandidateSelection()` writes a fallback provider
override with `authProfileOverrideSource: "auto"`, the override was
incorrectly preserved across `/reset` and `/new` commands. This caused
sessions to keep using the fallback provider even after the user changed
the agent config primary provider, because the session store override
takes precedence over the config default.

Now the override fields (`providerOverride`, `modelOverride`,
`authProfileOverride`, `authProfileOverrideSource`,
`authProfileOverrideCompactionCount`) are only carried forward when
`authProfileOverrideSource === "user"` (i.e. explicit `/model` command).
System-driven overrides are dropped on reset so the session picks up the
current config default.

Introduced in f0e2431 ("fix: preserve reset session behavior config")

* fix(gateway): preserve explicit reset model selection

* fix(gateway): track reset model override source

* fix(gateway): preserve legacy reset model overrides

* docs(changelog): add session reset merge note

---------

Co-authored-by: termtek <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime maintainer Maintainer-authored PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant