You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by zh...@apache.org on 2026/09/02 04:01:39 UTC

(maka) branch main updated: fix(desktop): make proxy credential updates explicit and Host-owned (#3704)

This is an automated email from the ASF dual-hosted git repository.

me2seeks pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/maka.git


The following commit(s) were added to refs/heads/main by this push:
     new 6c632b1339 fix(desktop): make proxy credential updates explicit and Host-owned (#3704)
6c632b1339 is described below

commit 6c632b1339053903b75ea1eada9eddc4ac08a9d0
Author: ooopSok <81...@users.noreply.github.com>
AuthorDate: Wed Sep 2 12:01:34 2026 +0800

    fix(desktop): make proxy credential updates explicit and Host-owned (#3704)
    
    * fix(desktop): prevent proxy password mask corruption
    
    Generated-by: OpenAI Codex
    
    * fix(runtime-host): make proxy updates recoverable
    
    Generated-by: OpenAI Codex
    
    * chore(test): update Windows skip inventory
    
    Generated-by: OpenAI Codex
    
    * fix(desktop): close proxy password review gaps
    
    Generated-by: OpenAI Codex
    
    * ci: retrigger checks
    
    Generated-by: OpenAI Codex
    
    * fix(storage): keep proxy secrets inside credential vault
    
    Generated-by: OpenAI Codex
    
    * ci: retrigger checks
    
    Generated-by: OpenAI Codex
    
    * chore(test): refresh Windows skip inventory
    
    Generated-by: OpenAI Codex
    
    * fix(desktop): address proxy password review findings
    
    * chore(test): refresh Windows skip inventory
    
    Generated-by: OpenAI Codex
    
    * fix(desktop): preserve credentials-only restores
    
    * fix(desktop): isolate proxy password draft feature
    
    * fix(desktop): avoid untracked proxy surface
    
    * fix(desktop): keep proxy test entry minimal
    
    * fix(desktop): expand sidebar in proxy e2e
    
    * fix(desktop): bind restored credentials to targets
    
    * fix(config): bind credential transfers to host targets
    
    * fix(config): reject unbound credential imports
    
    Generated-by: Codex
    
    * test(release): make state root qualification portable
    
    * fix(runtime-host): advance proxy protocol compatibility epoch
---
 apps/desktop/e2e/proxy-password-editing.spec.ts    | 152 +++++++
 apps/desktop/renderer-architecture.json            |   2 +-
 .../main/__tests__/config-transfer-service.test.ts | 177 +++++++-
 .../src/main/__tests__/password-input.test.ts      | 268 ++++++++++++
 .../main/__tests__/proxy-password-draft.test.ts    | 166 ++++++++
 .../__tests__/runtime-host-config-ipc-main.test.ts | 470 ++++++++++++++++++++-
 .../runtime-host-settings-ipc-main.test.ts         | 412 +++++++++++++++++-
 .../main/__tests__/settings-ipc-helpers.test.ts    |  42 +-
 .../main/__tests__/settings-resource-state.test.ts |  26 +-
 .../__tests__/settings-test-result-copy.test.ts    |  39 ++
 apps/desktop/src/main/config-transfer-service.ts   |  99 ++++-
 apps/desktop/src/main/runtime-host-boot.ts         |  21 +-
 apps/desktop/src/main/runtime-host-client.ts       |   6 +
 .../src/main/runtime-host-config-ipc-main.ts       | 370 +++++++++++++---
 .../src/main/runtime-host-settings-ipc-main.ts     | 316 ++++++++++----
 apps/desktop/src/main/settings-ipc-helpers.ts      |  83 +---
 apps/desktop/src/preload/bridge-contract.d.ts      |   5 +-
 apps/desktop/src/preload/preload.ts                |   5 +-
 .../controller/use-proxy-password-draft.ts         |  39 ++
 .../src/renderer/features/network-proxy/index.ts   |  35 ++
 .../network-proxy/model/proxy-password-draft.ts    | 105 +++++
 .../src/renderer/features/network-proxy/testing.ts |  23 +
 .../renderer/locales/settings-preferences-copy.ts  |   3 +
 .../renderer/locales/settings-test-result-copy.ts  |   6 +
 .../renderer/settings/general-settings-page.tsx    |  94 ++++-
 .../src/renderer/settings/password-input.tsx       |  34 +-
 .../renderer/settings/settings-snapshot-cache.ts   |   9 +-
 .../src/renderer/settings/settings-surface.tsx     |   8 +-
 .../stories/settings/settings-pages.stories.tsx    |  34 +-
 docs/windows-test-inventory.md                     |   8 +-
 packages/core/src/__tests__/settings.test.ts       |  35 ++
 packages/core/src/runtime-policy.ts                |  65 ++-
 .../src/runtime-policy/connection-catalog-codec.ts |  63 +++
 .../src/runtime-policy/credential-vault-codec.ts   |  16 +-
 packages/core/src/runtime-policy/policy-codec.ts   | 100 +++++
 packages/core/src/settings.ts                      |  62 ++-
 packages/core/src/settings/network-settings.ts     |   2 +-
 .../runtime-host/src/__tests__/protocol.test.ts    | 206 +++++++++
 .../__tests__/runtime-policy-coordinator.test.ts   | 166 +++++++-
 .../runtime-host/src/protocol/configuration.ts     |  91 +++-
 packages/runtime-host/src/protocol/index.ts        |   6 +-
 .../runtime-host/src/protocol/network-proxy.ts     |   9 +-
 packages/runtime-host/src/protocol/operations.ts   |   1 +
 .../runtime-host/src/protocol/runtime-policy.ts    |  76 ++++
 .../src/server/configuration-coordinator.ts        |  21 +-
 .../src/server/network-proxy-coordinator.ts        |   1 -
 .../src/server/runtime-policy-coordinator.ts       |  37 +-
 .../src/__tests__/runtime-policy-stores.test.ts    | 458 ++++++++++++++++++++
 .../__tests__/settings-store-onboarding.test.ts    |  39 ++
 packages/storage/src/runtime-policy-stores.ts      |  12 +-
 packages/storage/src/runtime-policy/coordinator.ts | 234 +++++++++-
 packages/storage/src/runtime-policy/operations.ts  |  22 +
 packages/storage/src/settings-store.ts             |  48 +--
 scripts/qualify-released-cli-state-root.test.mjs   |   5 +-
 54 files changed, 4431 insertions(+), 401 deletions(-)

diff --git a/apps/desktop/e2e/proxy-password-editing.spec.ts b/apps/desktop/e2e/proxy-password-editing.spec.ts
new file mode 100644
index 0000000000..879d1045f9
--- /dev/null
+++ b/apps/desktop/e2e/proxy-password-editing.spec.ts
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { createServer } from "node:http";
+import {
+  test,
+  expect,
+  COMPOSER_INPUT,
+  ensureSidebarExpanded,
+} from "./fixtures";
+
+test("proxy password drafts save once, reload safely, and authenticate offline", async ({
+  window: page,
+}) => {
+  const username = "proxy-user";
+  const password = "complete-secret";
+  const replacementPassword = "replacement-secret";
+  let acceptAuthorization!: (value: string | undefined) => void;
+  const authorization = new Promise<string | undefined>((resolve) => {
+    acceptAuthorization = resolve;
+  });
+  const proxy = createServer((request, response) => {
+    acceptAuthorization(request.headers["proxy-authorization"]);
+    response.writeHead(200, { "content-length": "0", connection: "close" });
+    response.end();
+  });
+  await new Promise<void>((resolve, reject) => {
+    proxy.once("error", reject);
+    proxy.listen(0, "127.0.0.1", () => resolve());
+  });
+  const address = proxy.address();
+  if (!address || typeof address === "string") {
+    throw new Error("Local proxy did not expose a TCP port");
+  }
+
+  try {
+    await ensureSidebarExpanded(page);
+    await page.getByRole("button", { name: "设置" }).click();
+    await page.getByRole("button", { name: "通用", exact: true }).click();
+    await page.getByRole("switch", { name: "启用代理服务器" }).click();
+    await page.getByRole("textbox", { name: "服务器地址" }).fill("127.0.0.1");
+    await page.getByRole("spinbutton", { name: "端口" }).fill(String(address.port));
+    await page.getByRole("switch", { name: "启用代理认证" }).click();
+    await page.getByRole("textbox", { name: "用户名" }).fill(username);
+
+    const passwordInput = page.getByRole("textbox", {
+      name: "密码 凭据值",
+      exact: true,
+    });
+    await passwordInput.pressSequentially(password);
+    await expect(passwordInput).toHaveValue(password);
+    await expect
+      .poll(() =>
+        page.evaluate(async () =>
+          (await window.maka.settings.get()).network.proxy.passwordConfigured,
+        ),
+      )
+      .toBe(false);
+
+    const eye = page.getByRole("button", { name: /显示|隐藏/ });
+    await eye.click();
+    await expect(passwordInput).toHaveAttribute("type", "text");
+    await expect(passwordInput).toHaveValue(password);
+    await expect
+      .poll(() =>
+        page.evaluate(async () =>
+          (await window.maka.settings.get()).network.proxy.passwordConfigured,
+        ),
+      )
+      .toBe(false);
+
+    await passwordInput.focus();
+    await page.keyboard.press("Tab");
+    await expect(eye).toBeFocused();
+    await expect
+      .poll(() =>
+        page.evaluate(async () =>
+          (await window.maka.settings.get()).network.proxy.passwordConfigured,
+        ),
+      )
+      .toBe(false);
+
+    await page.keyboard.press("Tab");
+    await expect
+      .poll(() =>
+        page.evaluate(async () =>
+          (await window.maka.settings.get()).network.proxy.passwordConfigured,
+        ),
+      )
+      .toBe(true);
+
+    await page.reload();
+    await page.waitForSelector(COMPOSER_INPUT);
+    await ensureSidebarExpanded(page);
+    await page.getByRole("button", { name: "设置" }).click();
+    await page.getByRole("button", { name: "通用", exact: true }).click();
+    const reloadedPassword = page.getByPlaceholder(
+      "密码已保存;输入新密码以替换",
+    );
+    await expect(reloadedPassword).toHaveValue("");
+    await expect(page.getByRole("button", { name: "复制" })).toHaveCount(0);
+
+    await reloadedPassword.pressSequentially("discarded-draft");
+    await expect(reloadedPassword).toHaveValue("discarded-draft");
+    await reloadedPassword.press("Escape");
+    await expect(reloadedPassword).toBeVisible();
+    await expect(reloadedPassword).toHaveValue("");
+
+    await reloadedPassword.pressSequentially(replacementPassword);
+    await eye.click();
+    await expect(reloadedPassword).toHaveAttribute("type", "text");
+    await expect(reloadedPassword).toHaveValue(replacementPassword);
+    await reloadedPassword.focus();
+    await reloadedPassword.press("Enter");
+    await expect(reloadedPassword).toHaveValue("");
+
+    await page.reload();
+    await page.waitForSelector(COMPOSER_INPUT);
+    await ensureSidebarExpanded(page);
+    await page.getByRole("button", { name: "设置" }).click();
+    await page.getByRole("button", { name: "通用", exact: true }).click();
+    await expect(
+      page.getByPlaceholder("密码已保存;输入新密码以替换"),
+    ).toHaveValue("");
+
+    const tested = await page.evaluate(() =>
+      window.maka.settings.testNetworkProxy({ url: "http://example.com" }),
+    );
+    expect(tested.ok).toBe(true);
+    expect(await authorization).toBe(
+      `Basic ${Buffer.from(`${username}:${replacementPassword}`).toString("base64")}`,
+    );
+  } finally {
+    await new Promise<void>((resolve) => proxy.close(() => resolve()));
+  }
+});
diff --git a/apps/desktop/renderer-architecture.json b/apps/desktop/renderer-architecture.json
index 02c3e00503..6d7402ca9d 100644
--- a/apps/desktop/renderer-architecture.json
+++ b/apps/desktop/renderer-architecture.json
@@ -3032,6 +3032,7 @@
         "actionFactories": [],
         "dependencyPaths": {
           "../features/connection-settings": 1,
+          "../features/network-proxy/index.js": 1,
           "../locales/settings-preferences-copy.js": 1,
           "../locales/settings-shared-copy.js": 1,
           "../locales/settings-test-result-copy.js": 1,
@@ -3050,7 +3051,6 @@
           "@maka/core/llm-connections": 1,
           "@maka/core/model-thinking": 1,
           "@maka/core/settings": 3,
-          "@maka/core/settings/network-settings": 1,
           "@maka/ui": 2,
           "react": 1
         }
diff --git a/apps/desktop/src/main/__tests__/config-transfer-service.test.ts b/apps/desktop/src/main/__tests__/config-transfer-service.test.ts
index a904296104..2d15fb0eab 100644
--- a/apps/desktop/src/main/__tests__/config-transfer-service.test.ts
+++ b/apps/desktop/src/main/__tests__/config-transfer-service.test.ts
@@ -19,12 +19,14 @@
 
 import { strict as assert } from 'node:assert';
 import { describe, it } from 'node:test';
-import type { AppSettings } from '@maka/core/settings';
 import type { LlmConnection } from '@maka/core/llm-connections';
 import type { CredentialKind } from '@maka/storage/credential-store';
 import { applyConfigImport, type ConfigTransferDeps } from '../config-transfer-service.js';
 
-function conn(slug: string): LlmConnection {
+function conn(
+  slug: string,
+  overrides: Partial<LlmConnection> = {},
+): LlmConnection {
   return {
     slug,
     name: slug,
@@ -33,6 +35,7 @@ function conn(slug: string): LlmConnection {
     enabled: true,
     createdAt: 1,
     updatedAt: 1,
+    ...overrides,
   };
 }
 
@@ -58,12 +61,13 @@ function makeDeps(overrides: Partial<ConfigTransferDeps> = {}): {
     settingsStore: {
       update: async (patch) => {
         updatedSettings.push(patch);
-        return patch as unknown as AppSettings;
+        return { skippedCredentials: 0 };
       },
     },
     credentialStore: {
-      setSecret: async (slug, kind, value) => {
+      setSecret: async ({ slug, kind, value }) => {
         setCreds.push({ slug, kind, value });
+        return true;
       },
     },
     writeMemory: async (content) => {
@@ -100,6 +104,28 @@ describe('config-transfer-service', () => {
     assert.deepEqual(writtenMemory, ['# imported memory']);
   });
 
+  it('reports a settings-carried proxy credential skipped by Host target binding', async () => {
+    const { deps } = makeDeps({
+      settingsStore: {
+        update: async () => ({ skippedCredentials: 1 }),
+      },
+    } as never);
+    const bundle = {
+      schemaVersion: 1,
+      exportedAt: '',
+      appVersion: '0.1.0',
+      includedData: ['settings', 'credentials'] as const,
+      data: {
+        settings: { network: { proxy: { credential: { kind: 'replace', secret: 'source' } } } },
+        credentials: [],
+      },
+    };
+
+    const result = await applyConfigImport(bundle as any, 'skip', deps);
+
+    assert.deepEqual(result.credentials, { applied: 0, skipped: 1 });
+  });
+
   it('restores the selection a backup states instead of re-enabling its default', async () => {
     // A backup can hold a connection whose default model the user had disabled.
     // `save()` cannot tell a stated selection from one a sync echoed back, so it
@@ -160,6 +186,149 @@ describe('config-transfer-service', () => {
     assert.deepEqual(setCreds, [{ slug: 'deepseek-main', kind: 'api_key', value: 'sk-new' }]);
     assert.deepEqual(result.credentials, { applied: 1, skipped: 0 });
   });
+
+  it('reports a Host-bound connection credential write that loses its target race', async () => {
+    const { deps, setCreds } = makeDeps({
+      credentialStore: {
+        setSecret: async () => false,
+      },
+    } as never);
+    const bundle = {
+      schemaVersion: 1,
+      exportedAt: '',
+      appVersion: '0.1.0',
+      includedData: ['connections', 'credentials'] as const,
+      data: {
+        connections: [conn('deepseek-main')],
+        credentials: [{ slug: 'deepseek-main', kind: 'api_key', value: 'source-secret' }],
+      },
+    };
+
+    const result = await applyConfigImport(bundle as any, 'overwrite', deps);
+
+    assert.deepEqual(setCreds, []);
+    assert.deepEqual(result.credentials, { applied: 0, skipped: 1 });
+  });
+
+  it('writes a credentials-only bundle to an existing connection', async () => {
+    const { deps, saved, setCreds } = makeDeps();
+    const bundle = {
+      schemaVersion: 1,
+      exportedAt: '',
+      appVersion: '0.1.0',
+      includedData: ['credentials'] as const,
+      data: {
+        credentials: [
+          {
+            slug: 'deepseek-main',
+            kind: 'api_key',
+            value: 'sk-restored',
+            connection: {
+              providerType: 'deepseek',
+              effectiveBaseUrl: 'https://api.deepseek.com',
+            },
+          },
+        ],
+      },
+    };
+
+    const result = await applyConfigImport(bundle as any, 'skip', deps);
+
+    assert.deepEqual(saved, [], 'credentials-only import does not rewrite the connection');
+    assert.deepEqual(setCreds, [
+      { slug: 'deepseek-main', kind: 'api_key', value: 'sk-restored' },
+    ]);
+    assert.deepEqual(result.credentials, { applied: 1, skipped: 0 });
+  });
+
+  it('skips a credentials-only entry without a source connection binding', async () => {
+    const { deps, setCreds } = makeDeps();
+    const bundle = {
+      schemaVersion: 1,
+      exportedAt: '',
+      appVersion: '0.1.0',
+      includedData: ['credentials'] as const,
+      data: {
+        credentials: [
+          {
+            slug: 'deepseek-main',
+            kind: 'api_key',
+            value: 'sk-unbound-source',
+          },
+        ],
+      },
+    };
+
+    const result = await applyConfigImport(bundle as any, 'skip', deps);
+
+    assert.deepEqual(setCreds, []);
+    assert.deepEqual(result.credentials, { applied: 0, skipped: 1 });
+  });
+
+  it('skips a credentials-only entry when the target slug belongs to another provider', async () => {
+    const { deps, setCreds } = makeDeps();
+    const bundle = {
+      schemaVersion: 1,
+      exportedAt: '',
+      appVersion: '0.1.0',
+      includedData: ['credentials'] as const,
+      data: {
+        credentials: [
+          {
+            slug: 'deepseek-main',
+            kind: 'api_key',
+            value: 'sk-openai-source',
+            connection: {
+              providerType: 'openai',
+              effectiveBaseUrl: 'https://api.openai.com/v1',
+            },
+          },
+        ],
+      },
+    };
+
+    const result = await applyConfigImport(bundle as any, 'skip', deps);
+
+    assert.deepEqual(setCreds, []);
+    assert.deepEqual(result.credentials, { applied: 0, skipped: 1 });
+  });
+
+  it('skips a credentials-only entry when the target endpoint differs', async () => {
+    const target = conn('deepseek-main', {
+      baseUrl: 'https://target-relay.example/v1',
+    });
+    const { deps, setCreds } = makeDeps({
+      connectionStore: {
+        list: async () => [target],
+        save: async (connection) => connection,
+      },
+    });
+    const bundle = {
+      schemaVersion: 1,
+      exportedAt: '',
+      appVersion: '0.1.0',
+      includedData: ['credentials'] as const,
+      data: {
+        credentials: [
+          {
+            slug: 'deepseek-main',
+            kind: 'api_key',
+            value: 'sk-source-endpoint',
+            connection: {
+              providerType: 'deepseek',
+              effectiveBaseUrl: 'https://api.deepseek.com',
+            },
+          },
+        ],
+      },
+    };
+
+    const result = await applyConfigImport(bundle as any, 'skip', deps);
+
+    assert.deepEqual(setCreds, []);
+    assert.deepEqual(result.credentials, { applied: 0, skipped: 1 });
+  });
+
   it('restores the whole bundle when it carries a retained retired connection', async () => {
     // A backup taken before the retirement still lists the connection, and the
     // catalog refuses to create one. Before this was planned as skipped, the
diff --git a/apps/desktop/src/main/__tests__/password-input.test.ts b/apps/desktop/src/main/__tests__/password-input.test.ts
new file mode 100644
index 0000000000..56d88a688e
--- /dev/null
+++ b/apps/desktop/src/main/__tests__/password-input.test.ts
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import assert from "node:assert/strict";
+import { mkdir, mkdtemp } from "node:fs/promises";
+import { dirname, resolve } from "node:path";
+import { pathToFileURL } from "node:url";
+import { afterEach, test } from "node:test";
+import { act, createElement } from "react";
+import { createRoot, type Root } from "react-dom/client";
+import { parseHTML } from "linkedom";
+import { build } from "esbuild";
+import {
+  AstryxLocaleProvider,
+  LocaleProvider,
+  ToastProvider,
+} from "@maka/ui";
+import type * as PasswordInputModule from "../../renderer/settings/password-input.js";
+
+const REPO_ROOT = resolve(import.meta.dirname, "../../../../..");
+
+const originalGlobals = {
+  document: globalThis.document,
+  window: globalThis.window,
+  HTMLElement: globalThis.HTMLElement,
+  Node: globalThis.Node,
+  Event: globalThis.Event,
+  IS_REACT_ACT_ENVIRONMENT: (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean })
+    .IS_REACT_ACT_ENVIRONMENT,
+};
+
+let mountedRoot: Root | undefined;
+
+afterEach(async () => {
+  if (mountedRoot) await act(() => mountedRoot?.unmount());
+  mountedRoot = undefined;
+  Object.assign(globalThis, originalGlobals);
+});
+
+test("mouse focus moving from the password draft to Eye does not commit and Eye reveals it", async () => {
+  const harness = await renderPasswordInputs();
+  const input = harness.document.querySelector("input") as HTMLInputElement;
+  const show = harness.document.querySelector(
+    'button[aria-label="Show"]',
+  ) as HTMLButtonElement;
+  assert.ok(input);
+  assert.ok(show);
+
+  harness.focusExit(input, show);
+  assert.equal(harness.exits, 0);
+  await act(async () => show.click());
+  assert.equal(input.type, "text");
+  assert.equal(input.value, "complete-secret");
+});
+
+test("keyboard focus stays inside through Eye and commits once when Tab leaves the group", async () => {
+  const harness = await renderPasswordInputs();
+  const input = harness.document.querySelector("input") as HTMLInputElement;
+  const show = harness.document.querySelector(
+    'button[aria-label="Show"]',
+  ) as HTMLButtonElement;
+  const outside = harness.document.querySelector("#outside") as HTMLButtonElement;
+
+  harness.focusExit(input, show);
+  assert.equal(harness.exits, 0);
+  harness.focusExit(show, outside);
+  assert.equal(harness.exits, 1);
+});
+
+test("window blur does not commit a partially typed password draft", async () => {
+  const harness = await renderPasswordInputs();
+  const input = harness.document.querySelector("input") as HTMLInputElement;
+
+  harness.setDocumentFocused(false);
+  harness.focusExit(input, null);
+
+  assert.equal(harness.exits, 0);
+});
+
+test("focus exit with no destination still commits while the document is focused", async () => {
+  const harness = await renderPasswordInputs();
+  const input = harness.document.querySelector("input") as HTMLInputElement;
+
+  harness.setDocumentFocused(true);
+  harness.focusExit(input, null);
+
+  assert.equal(harness.exits, 1);
+});
+
+test("proxy password can hide Copy while ordinary password inputs keep it by default", async () => {
+  const harness = await renderPasswordInputs();
+  const copyButtons = harness.document.querySelectorAll(
+    'button[aria-label="Copy"]',
+  );
+
+  assert.equal(copyButtons.length, 1);
+});
+
+test("IME confirmation keys do not submit or cancel the password draft", async () => {
+  const harness = await renderPasswordInputs();
+  const input = harness.document.querySelector("input") as HTMLInputElement;
+  const onKeyDown = reactProps(input).onKeyDown as (event: {
+    key: string;
+    nativeEvent: { isComposing?: boolean };
+  }) => void;
+
+  onKeyDown({ key: "Enter", nativeEvent: { isComposing: true } });
+  onKeyDown({ key: "Escape", nativeEvent: { isComposing: true } });
+  onKeyDown({ key: "Process", nativeEvent: {} });
+
+  assert.deepEqual(harness.keyEvents, { enters: 0, keys: [] });
+});
+
+test("non-composing Enter submits once and remains observable by the caller", async () => {
+  const harness = await renderPasswordInputs();
+  const input = harness.document.querySelector("input") as HTMLInputElement;
+  const onKeyDown = reactProps(input).onKeyDown as (event: {
+    key: string;
+    nativeEvent: { isComposing?: boolean };
+  }) => void;
+
+  onKeyDown({ key: "Enter", nativeEvent: { isComposing: false } });
+
+  assert.deepEqual(harness.keyEvents, { enters: 1, keys: ["Enter"] });
+});
+
+async function renderPasswordInputs(): Promise<{
+  document: Document;
+  readonly exits: number;
+  readonly keyEvents: { enters: number; keys: string[] };
+  focusExit(from: Element, to: Element | null): void;
+  setDocumentFocused(focused: boolean): void;
+}> {
+  const { PasswordInput } = await importPasswordInput();
+  const { document, window } = parseHTML(
+    '<div id="root"></div><button id="outside">outside</button>',
+  );
+  Object.assign(globalThis, {
+    document,
+    window,
+    HTMLElement: window.HTMLElement,
+    Node: window.Node,
+    Event: window.Event,
+    IS_REACT_ACT_ENVIRONMENT: true,
+  });
+  const container = document.querySelector("#root");
+  assert.ok(container);
+  const root = createRoot(container);
+  mountedRoot = root;
+  let exits = 0;
+  let enters = 0;
+  let documentFocused = true;
+  const keys: string[] = [];
+  Object.defineProperty(document, "hasFocus", {
+    configurable: true,
+    value: () => documentFocused,
+  });
+  await act(async () => {
+    root.render(
+      createElement(LocaleProvider, {
+        locale: "en",
+        children: createElement(AstryxLocaleProvider, {
+          children: createElement(ToastProvider, {
+            children: createElement("div", {},
+              createElement(PasswordInput, {
+                value: "complete-secret",
+                onChange() {},
+                onFocusExit: () => {
+                  exits += 1;
+                },
+                onEnter: () => {
+                  enters += 1;
+                },
+                onKeyDown: (event) => {
+                  keys.push(event.key);
+                },
+                hasCopyAction: false,
+                label: "Proxy password",
+              }),
+              createElement(PasswordInput, {
+                value: "ordinary-secret",
+                onChange() {},
+                label: "Ordinary password",
+              }),
+            ),
+          }),
+        }),
+      }),
+    );
+  });
+
+  const group = [...container.querySelectorAll("*")].find((element) => {
+    const props = reactProps(element);
+    return typeof props.onBlurCapture === "function";
+  });
+  assert.ok(group, "missing InputGroup focus boundary");
+  return {
+    document: document as unknown as Document,
+    get exits() {
+      return exits;
+    },
+    get keyEvents() {
+      return { enters, keys: [...keys] };
+    },
+    focusExit(_from, to) {
+      const handler = reactProps(group).onBlurCapture as (event: {
+        currentTarget: Element;
+        relatedTarget: Element | null;
+      }) => void;
+      handler({ currentTarget: group, relatedTarget: to });
+    },
+    setDocumentFocused(focused) {
+      documentFocused = focused;
+    },
+  };
+}
+
+async function importPasswordInput(): Promise<typeof PasswordInputModule> {
+  const outdir = await mkdtemp(
+    resolve(REPO_ROOT, "apps/desktop/dist/main/__tests__/password-input-"),
+  );
+  const outfile = resolve(outdir, "password-input.mjs");
+  await mkdir(dirname(outfile), { recursive: true });
+  await build({
+    entryPoints: [
+      resolve(
+        REPO_ROOT,
+        "apps/desktop/src/renderer/settings/password-input.tsx",
+      ),
+    ],
+    outfile,
+    bundle: true,
+    packages: "external",
+    platform: "node",
+    format: "esm",
+    jsx: "automatic",
+    target: "node20",
+    logLevel: "silent",
+  });
+  return (await import(
+    `${pathToFileURL(outfile).href}?t=${Date.now()}`
+  )) as typeof PasswordInputModule;
+}
+
+function reactProps(element: Element): Record<string, unknown> {
+  const key = Object.keys(element).find((candidate) =>
+    candidate.startsWith("__reactProps$"),
+  );
+  return key
+    ? ((element as unknown as Record<string, unknown>)[key] as Record<string, unknown>)
+    : {};
+}
diff --git a/apps/desktop/src/main/__tests__/proxy-password-draft.test.ts b/apps/desktop/src/main/__tests__/proxy-password-draft.test.ts
new file mode 100644
index 0000000000..be3eb22fc7
--- /dev/null
+++ b/apps/desktop/src/main/__tests__/proxy-password-draft.test.ts
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import assert from "node:assert/strict";
+import test from "node:test";
+import {
+  createProxyPasswordDraft,
+  runAfterProxyPasswordCommit,
+} from "../../renderer/features/network-proxy/testing.js";
+
+function deferred<T = void>() {
+  let resolve!: (value: T | PromiseLike<T>) => void;
+  let reject!: (reason?: unknown) => void;
+  const promise = new Promise<T>((onResolve, onReject) => {
+    resolve = onResolve;
+    reject = onReject;
+  });
+  return { promise, resolve, reject };
+}
+
+test("proxy password typing remains local until the complete draft is committed", async () => {
+  const saved: string[] = [];
+  const draft = createProxyPasswordDraft(async (secret) => {
+    saved.push(secret);
+  });
+
+  for (const value of ["s", "se", "sec", "secret"]) draft.edit(value);
+  assert.deepEqual(saved, []);
+  assert.equal(draft.value, "secret");
+
+  await draft.commit();
+  assert.deepEqual(saved, ["secret"]);
+  assert.equal(draft.value, "");
+});
+
+test("Enter followed by focus exit reuses one in-flight save", async () => {
+  const write = deferred();
+  let calls = 0;
+  const draft = createProxyPasswordDraft(async () => {
+    calls += 1;
+    await write.promise;
+  });
+  draft.edit("complete-secret");
+
+  const entered = draft.commit();
+  const blurred = draft.commit();
+
+  assert.equal(entered, blurred);
+  assert.equal(calls, 1);
+  write.resolve();
+  await entered;
+  assert.equal(draft.pending, false);
+});
+
+test("a failed save retains the complete draft for retry", async () => {
+  const draft = createProxyPasswordDraft(async () => {
+    throw new Error("save failed");
+  });
+  draft.edit("complete-secret");
+
+  await assert.rejects(draft.commit(), /save failed/);
+
+  assert.equal(draft.value, "complete-secret");
+  assert.equal(draft.pending, false);
+});
+
+test("an old save response never clears edits made while it was pending", async () => {
+  const first = deferred();
+  const saved: string[] = [];
+  const draft = createProxyPasswordDraft(async (secret) => {
+    saved.push(secret);
+    if (saved.length === 1) await first.promise;
+  });
+  draft.edit("first-secret");
+  const savingFirst = draft.commit();
+  draft.edit("second-secret");
+
+  first.resolve();
+  await savingFirst;
+  assert.equal(draft.value, "second-secret");
+
+  await draft.commit();
+  assert.deepEqual(saved, ["first-secret", "second-secret"]);
+  assert.equal(draft.value, "");
+});
+
+test("a test-time commit waits for an in-flight save then commits newer edits", async () => {
+  const first = deferred();
+  const saved: string[] = [];
+  const draft = createProxyPasswordDraft(async (secret) => {
+    saved.push(secret);
+    if (saved.length === 1) await first.promise;
+  });
+  draft.edit("first-secret");
+  void draft.commit();
+  draft.edit("latest-secret");
+
+  const beforeTest = draft.commit();
+  first.resolve();
+  await beforeTest;
+
+  assert.deepEqual(saved, ["first-secret", "latest-secret"]);
+  assert.equal(draft.value, "");
+});
+
+test("cancel clears only work that has not entered the save lane", async () => {
+  const write = deferred();
+  const draft = createProxyPasswordDraft(async () => write.promise);
+  draft.edit("queued-secret");
+  const saving = draft.commit();
+  draft.edit("unsubmitted-change");
+
+  draft.cancel();
+  assert.equal(draft.value, "queued-secret");
+
+  write.resolve();
+  await saving;
+  assert.equal(draft.value, "");
+
+  draft.edit("local-only");
+  draft.cancel();
+  assert.equal(draft.value, "");
+});
+
+test("empty drafts are keep operations", async () => {
+  let calls = 0;
+  const draft = createProxyPasswordDraft(async () => {
+    calls += 1;
+  });
+
+  await draft.commit();
+
+  assert.equal(calls, 0);
+});
+
+test("proxy testing waits for the save and aborts when that save fails", async () => {
+  const write = deferred();
+  let tests = 0;
+  const draft = createProxyPasswordDraft(async () => write.promise);
+  draft.edit("complete-secret");
+
+  const testing = runAfterProxyPasswordCommit(draft, async () => {
+    tests += 1;
+    return "tested";
+  });
+  assert.equal(tests, 0);
+  write.reject(new Error("save failed"));
+  await assert.rejects(testing, /save failed/);
+  assert.equal(tests, 0);
+});
diff --git a/apps/desktop/src/main/__tests__/runtime-host-config-ipc-main.test.ts b/apps/desktop/src/main/__tests__/runtime-host-config-ipc-main.test.ts
index d3095f08c6..a3b808d711 100644
--- a/apps/desktop/src/main/__tests__/runtime-host-config-ipc-main.test.ts
+++ b/apps/desktop/src/main/__tests__/runtime-host-config-ipc-main.test.ts
@@ -19,14 +19,21 @@
 
 import assert from 'node:assert/strict';
 import test from 'node:test';
-import type { AppSettings } from '@maka/core/settings';
+import {
+  createDefaultSettings,
+  type RuntimeHostAppSettings,
+} from '@maka/core/settings';
 import type {
   CredentialLocator,
 } from '@maka/core/runtime-policy';
+import type { ConfigBundle } from '@maka/storage/config-transfer';
+import {
+  adaptRuntimeHostConfigImport,
+  gatherRuntimeHostConfig,
+} from '../runtime-host-config-ipc-main.js';
 import type {
-  RuntimeHostConnectionCatalogEntry as ConnectionCatalogEntry,
   RuntimeHostConnectionCatalogSnapshot as ConnectionCatalogSnapshot,
-} from '@maka/runtime-host/client';import { gatherRuntimeHostConfig } from '../runtime-host-config-ipc-main.js';
+} from '@maka/runtime-host/client';
 
 const CATALOG: ConnectionCatalogSnapshot = {
   revision: 1,
@@ -69,6 +76,7 @@ test('Runtime Host config export omits settings secrets unless credentials are s
   assert.deepEqual(bundle.includedData, ['settings']);
   assert.equal(credentialExports, 0);
   assert.equal('password' in settings.network.proxy, false);
+  assert.equal('passwordConfigured' in settings.network.proxy, false);
   assert.equal('token' in settings.botChat.channels.telegram, false);
   assert.equal('appSecret' in settings.botChat.channels.telegram, false);
   assert.equal('apiKey' in settings.webSearch.providers.tavily, false);
@@ -87,10 +95,7 @@ test('Runtime Host config export reads selected credentials from Host authority'
             credential:
               secret === null
                 ? null
-                : {
-                    locator,
-                    secretBase64: Buffer.from(secret).toString('base64'),
-                  },
+                : exportedCredential(locator, secret),
           };
         },
       },
@@ -101,30 +106,436 @@ test('Runtime Host config export reads selected credentials from Host authority'
 
   const settings = bundle.data.settings as Record<string, any>;
   assert.deepEqual(bundle.data.credentials, [
-    { slug: 'deepseek-main', kind: 'api_key', value: 'sk-host' },
+    {
+      slug: 'deepseek-main',
+      kind: 'api_key',
+      value: 'sk-host',
+      connection: {
+        providerType: 'deepseek',
+        effectiveBaseUrl: 'https://api.deepseek.com/',
+      },
+    },
   ]);
   assert.equal(settings.network.proxy.password, 'proxy-host');
   assert.equal(settings.webSearch.providers.tavily.apiKey, 'tavily-host');
   assert.equal(settings.botChat.channels.telegram.token, 'bot-secret');
 });
 
-function settingsWithSecrets(): AppSettings {
-  return {
-    theme: 'dark',
-    network: { proxy: { host: '127.0.0.1', password: 'local-proxy-secret' } },
-    botChat: {
-      channels: {
-        telegram: {
-          chatId: '42',
-          token: 'bot-secret',
-          appSecret: 'app-secret',
+test('Runtime Host config export retries when a bound connection target changes', async () => {
+  const movedCatalog: ConnectionCatalogSnapshot = {
+    ...CATALOG,
+    revision: 2,
+    connections: [
+      {
+        ...CATALOG.connections[0]!,
+        revision: 2,
+        baseUrl: 'https://target-relay.example/v1',
+      },
+    ],
+  };
+  let catalogReads = 0;
+
+  const bundle = await gatherRuntimeHostConfig(
+    ['credentials'],
+    {
+      client: {
+        loadConnectionCatalog: async () => {
+          catalogReads += 1;
+          return catalogReads === 1 ? CATALOG : movedCatalog;
+        },
+        exportConfigurationCredentials: async ({
+          locator,
+          expectedConnection,
+        }: {
+          locator: CredentialLocator;
+          expectedConnection?: { revision: number };
+        }) => {
+          if (locator.scope !== 'connection') return { credential: null };
+          if (expectedConnection?.revision !== 2) {
+            return {
+              credential: null,
+              connectionStale: {
+                expected: {
+                  connectionId: CATALOG.connections[0]!.connectionId,
+                  revision: 1,
+                },
+                actual: {
+                  connectionId: CATALOG.connections[0]!.connectionId,
+                  revision: 2,
+                },
+              },
+            };
+          }
+          return locator.kind === 'api_key'
+            ? {
+                credential: {
+                  locator,
+                  secretBase64: Buffer.from('freshly-bound-secret').toString('base64'),
+                },
+              }
+            : { credential: null };
         },
       },
+      appVersion: '0.1.0',
+      getSettings: async () => settingsWithSecrets(),
+    } as never,
+  );
+
+  assert.equal(catalogReads, 2);
+  assert.deepEqual(bundle.data.credentials, [
+    {
+      slug: 'deepseek-main',
+      kind: 'api_key',
+      value: 'freshly-bound-secret',
+      connection: {
+        providerType: 'deepseek',
+        effectiveBaseUrl: 'https://target-relay.example/v1',
+      },
     },
-    webSearch: {
-      providers: { tavily: { apiKey: 'local-tavily-secret' } },
+  ]);
+});
+
+test('Runtime Host credentials-only export includes only schema-v1 credential fields', async () => {
+  const bundle = await gatherRuntimeHostConfig(
+    ['credentials'],
+    {
+      client: {
+        loadConnectionCatalog: async () => CATALOG,
+        exportConfigurationCredentials: async ({ locator }: { locator: CredentialLocator }) => {
+          const secret = secretFor(locator);
+          return {
+            credential:
+              secret === null
+                ? null
+                : exportedCredential(locator, secret),
+          };
+        },
+      },
+      appVersion: '0.1.0',
+      getSettings: async () => settingsWithSecrets(),
+    } as never,
+  );
+
+  assert.deepEqual(bundle.includedData, ['settings', 'credentials']);
+  assert.deepEqual(bundle.data.settings, {
+    network: {
+      proxy: {
+        password: 'proxy-host',
+        credentialTarget: {
+          protocol: 'http',
+          host: '127.0.0.1',
+          port: 7890,
+          username: '',
+        },
+      },
+    },
+    webSearch: { providers: { tavily: { apiKey: 'tavily-host' } } },
+  });
+  assert.deepEqual(bundle.data.credentials, [
+    {
+      slug: 'deepseek-main',
+      kind: 'api_key',
+      value: 'sk-host',
+      connection: {
+        providerType: 'deepseek',
+        effectiveBaseUrl: 'https://api.deepseek.com/',
+      },
+    },
+  ]);
+});
+
+test('Runtime Host credentials-only proxy export carries a target binding without patching policy', async () => {
+  const exported = await gatherRuntimeHostConfig(
+    ['credentials'],
+    {
+      client: {
+        loadConnectionCatalog: async () => ({ ...CATALOG, connections: [] }),
+        exportConfigurationCredentials: async ({ locator }: { locator: CredentialLocator }) => ({
+          credential:
+            locator.scope === 'network_proxy'
+              ? {
+                  ...exportedCredential(locator, 'proxy-host'),
+                }
+              : null,
+        }),
+      },
+      appVersion: '0.1.0',
+      getSettings: async () => createDefaultSettings(),
+    } as never,
+  );
+
+  const adapted = adaptRuntimeHostConfigImport(exported);
+  const importedProxy = (adapted.data.settings as Record<string, any>).network.proxy;
+
+  assert.deepEqual(importedProxy, {
+    credential: {
+      kind: 'replace',
+      secret: 'proxy-host',
+      expectedTarget: {
+        protocol: 'http',
+        host: '127.0.0.1',
+        port: 7890,
+        username: '',
+      },
     },
-  } as unknown as AppSettings;
+  });
+});
+
+test('Runtime Host settings export retries when the proxy changes after its secret read', async () => {
+  let exports = 0;
+  let settingsReads = 0;
+  const source = settingsWithSecrets();
+  source.network.proxy.enabled = true;
+  source.network.proxy.authEnabled = true;
+  source.network.proxy.host = 'proxy-a.example';
+  source.network.proxy.port = 8080;
+  source.network.proxy.username = 'source-user';
+
+  const bundle = await gatherRuntimeHostConfig(
+    ['settings', 'credentials'],
+    {
+      client: {
+        loadConnectionCatalog: async () => ({ ...CATALOG, connections: [] }),
+        exportConfigurationCredentials: async ({ locator }: { locator: CredentialLocator }) => {
+          if (locator.scope !== 'network_proxy') return { credential: null };
+          exports += 1;
+          return {
+            credential: {
+              locator,
+              secretBase64: Buffer.from('proxy-a-secret').toString('base64'),
+              proxyTarget: {
+                protocol: 'http' as const,
+                host: 'proxy-a.example',
+                port: 8080,
+                username: 'source-user',
+              },
+            },
+          };
+        },
+      },
+      appVersion: '0.1.0',
+      getSettings: async () => {
+        settingsReads += 1;
+        return settingsReads === 1
+          ? {
+              ...source,
+              network: {
+                proxy: {
+                  ...source.network.proxy,
+                  host: 'proxy-b.example',
+                },
+              },
+            }
+          : source;
+      },
+    } as never,
+  );
+
+  assert.equal(exports, 2);
+  const settings = bundle.data.settings as Record<string, any>;
+  assert.equal(settings.network.proxy.host, 'proxy-a.example');
+  assert.equal(settings.network.proxy.password, 'proxy-a-secret');
+});
+
+test('Runtime Host credentials-only export omits each absent settings-carried secret', async () => {
+  const cases = [
+    {
+      presentScope: 'web_search',
+      expected: {
+        webSearch: { providers: { tavily: { apiKey: 'tavily-host' } } },
+      },
+    },
+    {
+      presentScope: 'network_proxy',
+      expected: {
+        network: {
+          proxy: {
+            password: 'proxy-host',
+            credentialTarget: {
+              protocol: 'http',
+              host: '127.0.0.1',
+              port: 7890,
+              username: '',
+            },
+          },
+        },
+      },
+    },
+    {
+      presentScope: null,
+      expected: undefined,
+    },
+  ] as const;
+
+  for (const { presentScope, expected } of cases) {
+    const bundle = await gatherRuntimeHostConfig(
+      ['credentials'],
+      {
+        client: {
+          loadConnectionCatalog: async () => ({ ...CATALOG, connections: [] }),
+          exportConfigurationCredentials: async ({
+            locator,
+          }: {
+            locator: CredentialLocator;
+          }) => {
+            const secret = locator.scope === presentScope ? secretFor(locator) : null;
+            return {
+              credential:
+                secret === null
+                  ? null
+                  : exportedCredential(locator, secret),
+            };
+          },
+        },
+        appVersion: '0.1.0',
+        getSettings: async () => settingsWithSecrets(),
+      } as never,
+    );
+
+    assert.deepEqual(bundle.data.settings, expected);
+    assert.deepEqual(
+      bundle.includedData,
+      expected === undefined ? ['credentials'] : ['settings', 'credentials'],
+    );
+  }
+});
+
+test('Runtime Host config export writes an empty v1 proxy password when none is configured', async () => {
+  const bundle = await gatherRuntimeHostConfig(
+    ['settings', 'credentials'],
+    {
+      client: {
+        loadConnectionCatalog: async () => ({ ...CATALOG, connections: [] }),
+        exportConfigurationCredentials: async () => ({ credential: null }),
+      },
+      appVersion: '0.1.0',
+      getSettings: async () => settingsWithSecrets(),
+    } as never,
+  );
+
+  const settings = bundle.data.settings as Record<string, any>;
+  assert.equal(settings.network.proxy.password, '');
+  assert.equal('passwordConfigured' in settings.network.proxy, false);
+});
+
+test('Runtime Host config import adapts v1 proxy passwords only with credential consent', () => {
+  const replaceBundle = importBundle(['settings', 'credentials'], 'complete-secret');
+  (replaceBundle.data.settings as Record<string, any>).network.proxy.credentialTarget = {
+    protocol: 'https',
+    host: 'Source.Proxy.Example',
+    port: 8443,
+    username: 'source-user',
+  };
+  const replace = adaptRuntimeHostConfigImport(replaceBundle);
+  assert.deepEqual(
+    (replace.data.settings as Record<string, any>).network.proxy,
+    {
+      host: '10.0.0.2',
+      credential: {
+        kind: 'replace',
+        secret: 'complete-secret',
+        expectedTarget: {
+          protocol: 'https',
+          host: 'source.proxy.example',
+          port: 8443,
+          username: 'source-user',
+        },
+      },
+    },
+  );
+
+  const remove = adaptRuntimeHostConfigImport(
+    importBundle(['settings', 'credentials'], ''),
+  );
+  assert.deepEqual(
+    (remove.data.settings as Record<string, any>).network.proxy.credential,
+    { kind: 'delete' },
+  );
+
+  const keep = adaptRuntimeHostConfigImport(
+    importBundle(['settings', 'credentials'], undefined),
+  );
+  assert.equal(
+    'credential' in (keep.data.settings as Record<string, any>).network.proxy,
+    false,
+  );
+
+  const ignored = adaptRuntimeHostConfigImport(
+    importBundle(['settings'], 'handcrafted-secret'),
+  );
+  assert.deepEqual(
+    (ignored.data.settings as Record<string, any>).network.proxy,
+    { host: '10.0.0.2' },
+  );
+});
+
+test('Runtime Host config import rejects an unbound legacy proxy password', () => {
+  assert.throws(
+    () =>
+      adaptRuntimeHostConfigImport(
+        importBundle(['settings', 'credentials'], 'legacy-secret'),
+      ),
+    /proxy.*target.*binding/i,
+  );
+});
+
+test('Runtime Host config import rejects a non-string v1 password during preflight', () => {
+  assert.throws(
+    () => adaptRuntimeHostConfigImport(importBundle(['settings', 'credentials'], 42)),
+    /password.*string/i,
+  );
+});
+
+test('Runtime Host config import rejects conflicting authentication before apply', () => {
+  const bundle = importBundle(
+    ['connections', 'settings', 'credentials'],
+    'complete-secret',
+  );
+  (bundle.data.settings as Record<string, any>).network.proxy.authEnabled = false;
+
+  assert.throws(
+    () => adaptRuntimeHostConfigImport(bundle),
+    /authentication.*disabled/i,
+  );
+});
+
+function settingsWithSecrets(): RuntimeHostAppSettings {
+  const settings = createDefaultSettings();
+  settings.botChat.channels.telegram.token = 'bot-secret';
+  settings.botChat.channels.telegram.appSecret = 'app-secret';
+  (settings.webSearch.providers.tavily as { apiKey: string }).apiKey =
+    'local-tavily-secret';
+  return {
+    ...settings,
+    network: {
+      proxy: {
+        ...settings.network.proxy,
+        passwordConfigured: true,
+      },
+    },
+  };
+}
+
+function importBundle(
+  includedData: ConfigBundle['includedData'],
+  password: unknown,
+): ConfigBundle {
+  const proxy: Record<string, unknown> = {
+    host: '10.0.0.2',
+    passwordConfigured: true,
+    credential: { kind: 'replace', secret: 'injected-operation' },
+  };
+  if (password !== undefined) proxy.password = password;
+  return {
+    schemaVersion: 1,
+    exportedAt: '',
+    appVersion: '',
+    includedData,
+    data: {
+      settings: { network: { proxy } },
+      ...(includedData.includes('credentials') ? { credentials: [] } : {}),
+    },
+  };
 }
 
 function secretFor(locator: CredentialLocator): string | null {
@@ -135,3 +546,20 @@ function secretFor(locator: CredentialLocator): string | null {
   }
   return null;
 }
+
+function exportedCredential(locator: CredentialLocator, secret: string) {
+  return {
+    locator,
+    secretBase64: Buffer.from(secret).toString('base64'),
+    ...(locator.scope === 'network_proxy'
+      ? {
+          proxyTarget: {
+            protocol: 'http' as const,
+            host: '127.0.0.1',
+            port: 7890,
+            username: '',
+          },
+        }
+      : {}),
+  };
+}
diff --git a/apps/desktop/src/main/__tests__/runtime-host-settings-ipc-main.test.ts b/apps/desktop/src/main/__tests__/runtime-host-settings-ipc-main.test.ts
index b11c39fc5b..63bd715226 100644
--- a/apps/desktop/src/main/__tests__/runtime-host-settings-ipc-main.test.ts
+++ b/apps/desktop/src/main/__tests__/runtime-host-settings-ipc-main.test.ts
@@ -19,11 +19,20 @@
 
 import assert from "node:assert/strict";
 import test from "node:test";
+import {
+  createDefaultSettings,
+  type UpdateAppSettingsInput,
+} from "@maka/core/settings";
 import {
   createDefaultRuntimePolicy,
   type RuntimePolicy,
+  type UpdateNetworkProxyInput,
 } from "@maka/core/runtime-policy";
-import { registerRuntimeHostSettingsIpc } from "../runtime-host-settings-ipc-main.js";
+import {
+  createRuntimeHostSettingsModule,
+  registerRuntimeHostSettingsIpc,
+  runRuntimeHostSettingsExclusive,
+} from "../runtime-host-settings-ipc-main.js";
 
 type TestCandidate = RuntimePolicy["networkProxy"];
 
@@ -35,12 +44,7 @@ async function testCandidate(authEnabled: boolean): Promise<{
   const policy = createDefaultRuntimePolicy();
   let candidate: TestCandidate | undefined;
 
-  registerRuntimeHostSettingsIpc({
-    ipcMain: {
-      handle(channel, listener) {
-        handlers.set(channel, listener as (...args: unknown[]) => unknown);
-      },
-    },
+  const module = createRuntimeHostSettingsModule({
     client: {
       async queryRuntimePolicy() {
         return { revision: 0, policy };
@@ -59,6 +63,14 @@ async function testCandidate(authEnabled: boolean): Promise<{
     settingsStore: {} as never,
     async applyClientSettings() {},
   });
+  registerRuntimeHostSettingsIpc({
+    ipcMain: {
+      handle(channel, listener) {
+        handlers.set(channel, listener as (...args: unknown[]) => unknown);
+      },
+    },
+    module,
+  });
 
   const handler = handlers.get("settings:testNetworkProxy");
   assert.ok(handler);
@@ -85,7 +97,7 @@ test("proxy test preserves enabled authentication when credentials are empty", a
 
   assert.equal(tested.candidate.authEnabled, true);
   assert.equal(tested.result.ok, false);
-  assert.equal(tested.result.code, "proxy_unreachable");
+  assert.equal(tested.result.code, "proxy_credential_missing");
 });
 
 test("proxy test preserves disabled authentication for a local proxy", async () => {
@@ -95,3 +107,387 @@ test("proxy test preserves disabled authentication for a local proxy", async ()
   assert.equal(tested.result.ok, true);
   assert.equal(tested.result.code, "proxy_reachable");
 });
+
+function createModuleFixture(options: {
+  configured?: boolean;
+  beforeSetCredential?: () => Promise<void>;
+  failFirstSet?: boolean;
+  proxyTargetMismatch?: boolean;
+} = {}) {
+  let policy = createDefaultRuntimePolicy();
+  if (options.configured) {
+    policy = {
+      ...policy,
+      networkProxy: { ...policy.networkProxy, authEnabled: true },
+    };
+  }
+  let policyRevision = 1;
+  let secret = options.configured ? "saved-secret" : undefined;
+  let revision = secret ? 1 : 0;
+  let failFirstSet = options.failFirstSet ?? false;
+  const events: string[] = [];
+  const local = createDefaultSettings();
+
+  const client = {
+    async queryRuntimePolicy() {
+      return { revision: policyRevision, policy };
+    },
+    async updateRuntimePolicy(
+      createMutation: (value: RuntimePolicy) => {
+        kind: string;
+        value: RuntimePolicy["networkProxy"];
+      },
+    ) {
+      const mutation = createMutation(policy);
+      if (mutation.kind === "set_network_proxy") {
+        policy = { ...policy, networkProxy: mutation.value };
+      }
+      policyRevision += 1;
+      return { revision: policyRevision, policy };
+    },
+    async updateNetworkProxy(input: UpdateNetworkProxyInput) {
+      if (input.expectedPolicyRevision !== policyRevision) {
+        return {
+          kind: "revision_conflict" as const,
+          expectedRevision: input.expectedPolicyRevision,
+          actualRevision: policyRevision,
+        };
+      }
+      if (options.proxyTargetMismatch && input.credential.kind === "replace") {
+        return {
+          kind: "proxy_target_mismatch" as const,
+          expected: input.credential.expectedTarget!,
+          actual: {
+            protocol: "http" as const,
+            host: "proxy-b.example",
+            port: 8080,
+            username: "target-user",
+          },
+        };
+      }
+      if (input.credential.kind === "replace") {
+        events.push(`set:${input.credential.secret}`);
+        await options.beforeSetCredential?.();
+        if (failFirstSet) {
+          failFirstSet = false;
+          throw new Error("credential write failed");
+        }
+        secret = input.credential.secret;
+        revision += 1;
+      } else if (input.credential.kind === "delete") {
+        events.push("delete");
+        secret = undefined;
+        revision += 1;
+      }
+      policy = { ...policy, networkProxy: input.networkProxy };
+      policyRevision += 1;
+      return {
+        kind: "committed" as const,
+        revision: policyRevision,
+        credentialStatus:
+          secret === undefined
+            ? {
+                locator: { scope: "network_proxy" as const, kind: "password" as const },
+                configured: false as const,
+                credentialId: null,
+                revision: null,
+                updatedAt: null,
+              }
+            : {
+                locator: { scope: "network_proxy" as const, kind: "password" as const },
+                configured: true as const,
+                credentialId: "proxy-credential",
+                revision,
+                updatedAt: 1,
+              },
+      };
+    },
+    async queryCredential(locator: { scope: string }) {
+      if (locator.scope !== "network_proxy" || secret === undefined) return null;
+      return {
+        locator: { scope: "network_proxy", kind: "password" },
+        configured: true,
+        credentialId: "proxy-credential",
+        revision,
+        updatedAt: 1,
+      };
+    },
+    async setCredential(input: { secret: string }) {
+      events.push(`set:${input.secret}`);
+      await options.beforeSetCredential?.();
+      if (failFirstSet) {
+        failFirstSet = false;
+        throw new Error("credential write failed");
+      }
+      secret = input.secret;
+      revision += 1;
+      return { kind: "committed", snapshot: { revision, entries: [] } };
+    },
+    async deleteCredential() {
+      events.push("delete");
+      secret = undefined;
+      revision += 1;
+      return { kind: "committed", snapshot: { revision, entries: [] } };
+    },
+    async testNetworkProxy() {
+      events.push("test");
+      return { ok: true, latencyMs: 1, status: 200 };
+    },
+  };
+
+  const module = createRuntimeHostSettingsModule({
+    client: client as never,
+    settingsStore: {
+      async get() {
+        return local;
+      },
+      async update(_patch: UpdateAppSettingsInput) {
+        return local;
+      },
+    } as never,
+    async applyClientSettings() {},
+  });
+
+  return {
+    module,
+    events,
+    policy: () => policy,
+    secret: () => secret,
+  };
+}
+
+test("runtime settings project credential status without a password value", async () => {
+  const fixture = createModuleFixture({ configured: true });
+
+  const settings = await fixture.module.get();
+
+  assert.equal(settings.network.proxy.passwordConfigured, true);
+  assert.equal("password" in settings.network.proxy, false);
+});
+
+test("spread-back derived and legacy password fields never enter Runtime policy", async () => {
+  const fixture = createModuleFixture({ configured: true });
+
+  await fixture.module.update({
+    network: {
+      proxy: {
+        host: "10.0.0.2",
+        passwordConfigured: true,
+        password: "legacy-secret",
+      } as never,
+    },
+  });
+
+  assert.equal(fixture.policy().networkProxy.host, "10.0.0.2");
+  assert.equal("passwordConfigured" in fixture.policy().networkProxy, false);
+  assert.equal("password" in fixture.policy().networkProxy, false);
+});
+
+test("proxy credential operations validate before any write", async () => {
+  for (const proxy of [
+    {
+      credential: { kind: "replace", secret: "" },
+    },
+    {
+      authEnabled: false,
+      credential: { kind: "replace", secret: "new-secret" },
+    },
+  ] satisfies Array<NonNullable<UpdateAppSettingsInput["network"]>["proxy"]>) {
+    const fixture = createModuleFixture({ configured: true });
+    await assert.rejects(
+      fixture.module.update({ network: { proxy } }),
+      /credential|password|authentication/i,
+    );
+    assert.deepEqual(fixture.events, []);
+    assert.equal(fixture.secret(), "saved-secret");
+  }
+});
+
+test("disabling the proxy keeps credentials while disabling authentication removes them", async () => {
+  const fixture = createModuleFixture({ configured: true });
+
+  await fixture.module.update({ network: { proxy: { enabled: false } } });
+  assert.equal(fixture.secret(), "saved-secret");
+
+  await fixture.module.update({
+    network: { proxy: { authEnabled: false } },
+  });
+  assert.equal(fixture.secret(), undefined);
+  assert.deepEqual(fixture.events, ["delete"]);
+});
+
+test("keep, replace, and explicit delete preserve the derived credential contract", async () => {
+  const fixture = createModuleFixture({ configured: true });
+
+  const kept = await fixture.module.update({
+    network: { proxy: { username: "updated-user" } },
+  });
+  assert.equal(fixture.secret(), "saved-secret");
+  assert.equal(kept.network.proxy.passwordConfigured, true);
+
+  const replaced = await fixture.module.update({
+    network: {
+      proxy: {
+        authEnabled: true,
+        credential: { kind: "replace", secret: "replacement" },
+      },
+    },
+  });
+  assert.equal(fixture.secret(), "replacement");
+  assert.equal(replaced.network.proxy.passwordConfigured, true);
+
+  const deleted = await fixture.module.update({
+    network: {
+      proxy: { authEnabled: true, credential: { kind: "delete" } },
+    },
+  });
+  assert.equal(fixture.policy().networkProxy.authEnabled, true);
+  assert.equal(fixture.secret(), undefined);
+  assert.equal(deleted.network.proxy.passwordConfigured, false);
+});
+
+test("config import skips a proxy password whose bound target no longer matches", async () => {
+  const fixture = createModuleFixture({ configured: true, proxyTargetMismatch: true });
+
+  const imported = await runRuntimeHostSettingsExclusive(
+    fixture.module,
+    (settings) =>
+      settings.updateForConfigImport({
+        network: {
+          proxy: {
+            credential: {
+              kind: "replace",
+              secret: "source-import-secret",
+              expectedTarget: {
+                protocol: "http",
+                host: "proxy-a.example",
+                port: 8080,
+                username: "source-user",
+              },
+            },
+          },
+        },
+      }),
+  );
+
+  assert.equal(imported.skippedCredentials, 1);
+  assert.equal(fixture.secret(), "saved-secret");
+  assert.deepEqual(fixture.events, []);
+});
+
+test("a later authentication disable waits for an in-flight replacement and wins", async () => {
+  let release!: () => void;
+  const blocked = new Promise<void>((resolve) => {
+    release = resolve;
+  });
+  const fixture = createModuleFixture({ beforeSetCredential: () => blocked });
+
+  const replace = fixture.module.update({
+    network: {
+      proxy: {
+        authEnabled: true,
+        credential: { kind: "replace", secret: "complete-secret" },
+      },
+    },
+  });
+  await new Promise((resolve) => setImmediate(resolve));
+  const disable = fixture.module.update({
+    network: { proxy: { authEnabled: false } },
+  });
+
+  assert.deepEqual(fixture.events, ["set:complete-secret"]);
+  release();
+  await Promise.all([replace, disable]);
+  assert.deepEqual(fixture.events, ["set:complete-secret", "delete"]);
+  assert.equal(fixture.secret(), undefined);
+});
+
+test("proxy tests wait for the lane and a failed operation does not poison it", async () => {
+  let release!: () => void;
+  const blocked = new Promise<void>((resolve) => {
+    release = resolve;
+  });
+  const fixture = createModuleFixture({
+    beforeSetCredential: () => blocked,
+    failFirstSet: true,
+  });
+  const replace = fixture.module.update({
+    network: {
+      proxy: {
+        authEnabled: true,
+        credential: { kind: "replace", secret: "complete-secret" },
+      },
+    },
+  });
+  await new Promise((resolve) => setImmediate(resolve));
+  const testResult = fixture.module.testNetworkProxy({});
+
+  assert.deepEqual(fixture.events, ["set:complete-secret"]);
+  release();
+  await assert.rejects(replace, /failed/);
+  assert.equal((await testResult).ok, true);
+  assert.deepEqual(fixture.events, ["set:complete-secret", "test"]);
+});
+
+test("a failed credential replacement does not commit proxy policy fields", async () => {
+  const fixture = createModuleFixture({ configured: true, failFirstSet: true });
+  const before = structuredClone(fixture.policy().networkProxy);
+
+  await assert.rejects(
+    fixture.module.update({
+      network: {
+        proxy: {
+          enabled: true,
+          host: "replacement.proxy.internal",
+          authEnabled: true,
+          username: "replacement-user",
+          credential: { kind: "replace", secret: "replacement-secret" },
+        },
+      },
+    }),
+    /failed/,
+  );
+
+  assert.deepEqual(fixture.policy().networkProxy, before);
+  assert.equal(fixture.secret(), "saved-secret");
+});
+
+test("compound config operations share the lane without re-entering it", async () => {
+  let release!: () => void;
+  const blocked = new Promise<void>((resolve) => {
+    release = resolve;
+  });
+  const fixture = createModuleFixture({ beforeSetCredential: () => blocked });
+  const replace = fixture.module.update({
+    network: {
+      proxy: {
+        authEnabled: true,
+        credential: { kind: "replace", secret: "complete-secret" },
+      },
+    },
+  });
+  await new Promise((resolve) => setImmediate(resolve));
+
+  const config = runRuntimeHostSettingsExclusive(
+    fixture.module,
+    async (settings) => {
+      fixture.events.push("config:start");
+      await settings.update({ network: { proxy: { username: "imported-user" } } });
+      const projected = await settings.get();
+      fixture.events.push("config:end");
+      return projected;
+    },
+  );
+  await new Promise((resolve) => setImmediate(resolve));
+  assert.deepEqual(fixture.events, ["set:complete-secret"]);
+
+  release();
+  await replace;
+  const projected = await config;
+  assert.equal(projected.network.proxy.username, "imported-user");
+  assert.deepEqual(fixture.events, [
+    "set:complete-secret",
+    "config:start",
+    "config:end",
+  ]);
+});
diff --git a/apps/desktop/src/main/__tests__/settings-ipc-helpers.test.ts b/apps/desktop/src/main/__tests__/settings-ipc-helpers.test.ts
index 12aca10f85..f905cba983 100644
--- a/apps/desktop/src/main/__tests__/settings-ipc-helpers.test.ts
+++ b/apps/desktop/src/main/__tests__/settings-ipc-helpers.test.ts
@@ -24,26 +24,22 @@ import { SENSITIVE_PLACEHOLDER } from "@maka/core/settings/network-settings";
 import {
   buildSettingsUpdateResult,
   maskAppSettings,
-  preserveSensitivePlaceholders,
   toSettingsTestResult,
 } from "../settings-ipc-helpers.js";
 
 describe("settings IPC helpers", () => {
-  test("masks sensitive network and bot fields before returning settings to renderer", () => {
+  test("masks sensitive bot fields before returning settings to renderer", () => {
     const settings = createDefaultSettings();
-    settings.network.proxy.password = "proxy-secret";
     settings.botChat.channels.telegram.token = "telegram-secret";
     settings.botChat.channels.feishu.appSecret = "feishu-secret";
 
     const masked = maskAppSettings(settings);
 
-    assert.equal(masked.network.proxy.password, SENSITIVE_PLACEHOLDER);
     assert.equal(masked.botChat.channels.telegram.token, SENSITIVE_PLACEHOLDER);
     assert.equal(
       masked.botChat.channels.feishu.appSecret,
       SENSITIVE_PLACEHOLDER,
     );
-    assert.equal(settings.network.proxy.password, "proxy-secret");
   });
 
   test("keeps empty sensitive fields empty instead of showing a placeholder", () => {
@@ -51,7 +47,6 @@ describe("settings IPC helpers", () => {
 
     const masked = maskAppSettings(settings);
 
-    assert.equal(masked.network.proxy.password, "");
     assert.equal(masked.botChat.channels.telegram.token, "");
   });
 
@@ -72,16 +67,13 @@ describe("settings IPC helpers", () => {
 
   test("reveals sensitive fields only when the current patch explicitly changes them", () => {
     const settings = createDefaultSettings();
-    settings.network.proxy.password = "new-proxy-secret";
     settings.botChat.channels.telegram.token = "new-bot-token";
     settings.botChat.channels.feishu.appSecret = "stored-feishu-secret";
 
     const masked = maskAppSettings(settings, {
-      network: { proxy: { password: "new-proxy-secret" } },
       botChat: { channels: { telegram: { token: "new-bot-token" } } },
     });
 
-    assert.equal(masked.network.proxy.password, "new-proxy-secret");
     assert.equal(masked.botChat.channels.telegram.token, "new-bot-token");
     assert.equal(
       masked.botChat.channels.feishu.appSecret,
@@ -105,38 +97,6 @@ describe("settings IPC helpers", () => {
     assert.equal(masked.webSearch.providers.tavily.credentialSource, "saved");
   });
 
-  test("preserves placeholder values as stored secrets before persisting patches", () => {
-    const current = createDefaultSettings();
-    current.network.proxy.password = "stored-proxy-secret";
-    current.botChat.channels.telegram.token = "stored-bot-token";
-    current.botChat.channels.feishu.appSecret = "stored-feishu-secret";
-
-    const patch = preserveSensitivePlaceholders(
-      {
-        network: {
-          proxy: { password: SENSITIVE_PLACEHOLDER, host: "10.0.0.2" },
-        },
-        botChat: {
-          channels: {
-            telegram: { token: SENSITIVE_PLACEHOLDER, enabled: true },
-            feishu: { appSecret: SENSITIVE_PLACEHOLDER, appId: "cli_123" },
-          },
-        },
-      },
-      current,
-    );
-
-    assert.equal(patch.network?.proxy?.password, "stored-proxy-secret");
-    assert.equal(patch.network?.proxy?.host, "10.0.0.2");
-    assert.equal(patch.botChat?.channels?.telegram?.token, "stored-bot-token");
-    assert.equal(patch.botChat?.channels?.telegram?.enabled, true);
-    assert.equal(
-      patch.botChat?.channels?.feishu?.appSecret,
-      "stored-feishu-secret",
-    );
-    assert.equal(patch.botChat?.channels?.feishu?.appId, "cli_123");
-  });
-
   test("maps runtime bot test results as credential checks, not operational readiness", () => {
     const result = toSettingsTestResult("telegram", {
       ok: true,
diff --git a/apps/desktop/src/main/__tests__/settings-resource-state.test.ts b/apps/desktop/src/main/__tests__/settings-resource-state.test.ts
index 8deb6fff8c..22f8bb6dec 100644
--- a/apps/desktop/src/main/__tests__/settings-resource-state.test.ts
+++ b/apps/desktop/src/main/__tests__/settings-resource-state.test.ts
@@ -19,7 +19,10 @@
 
 import { strict as assert } from 'node:assert';
 import { describe, it } from 'node:test';
-import { createDefaultSettings } from '@maka/core/settings';
+import {
+  createDefaultSettings,
+  type RuntimeHostAppSettings,
+} from '@maka/core/settings';
 import {
   beginSettingsResourceLoad,
   completeSettingsResourceLoad,
@@ -40,6 +43,19 @@ import { createSettingsRequestAuthority } from '../../renderer/settings/settings
 const LOCAL_KEY = 'local:host-local-1';
 const REMOTE_KEY = 'remote:host-remote-1';
 
+function runtimeHostSettings(): RuntimeHostAppSettings {
+  const settings = createDefaultSettings();
+  return {
+    ...settings,
+    network: {
+      proxy: {
+        ...settings.network.proxy,
+        passwordConfigured: false,
+      },
+    },
+  };
+}
+
 function catalog(entries: DesktopRuntimeHostProfileSnapshot['entries']): DesktopRuntimeHostProfileSnapshot {
   return {
     defaultProfileId: 'local',
@@ -188,9 +204,9 @@ describe('Settings snapshot cache', () => {
 
   it('isolates settings and connections by selected Runtime Host key', () => {
     const cache = createSettingsSnapshotCache();
-    const localSettings = createDefaultSettings();
+    const localSettings = runtimeHostSettings();
     const remoteSettings = {
-      ...createDefaultSettings(),
+      ...runtimeHostSettings(),
       personalization: {
         ...createDefaultSettings().personalization,
         displayName: 'Remote Host',
@@ -210,7 +226,7 @@ describe('Settings snapshot cache', () => {
 
   it('prunes snapshots when a profile reconnects with a new host id', () => {
     const cache = createSettingsSnapshotCache();
-    cache.commitRuntimeHostSettingsRead(LOCAL_KEY, createDefaultSettings());
+    cache.commitRuntimeHostSettingsRead(LOCAL_KEY, runtimeHostSettings());
     cache.commitRuntimeHostConnectionsRead(LOCAL_KEY, {
       connections: [],
       defaultSlug: null,
@@ -232,7 +248,7 @@ describe('Settings snapshot cache', () => {
 
   it('stores settings and connection reads independently', () => {
     const cache = createSettingsSnapshotCache();
-    const settings = createDefaultSettings();
+    const settings = runtimeHostSettings();
     cache.commitRuntimeHostSettingsRead(LOCAL_KEY, settings);
 
     assert.equal(cache.readRuntimeHostSettings(LOCAL_KEY), settings);
diff --git a/apps/desktop/src/main/__tests__/settings-test-result-copy.test.ts b/apps/desktop/src/main/__tests__/settings-test-result-copy.test.ts
new file mode 100644
index 0000000000..757ced374c
--- /dev/null
+++ b/apps/desktop/src/main/__tests__/settings-test-result-copy.test.ts
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import assert from "node:assert/strict";
+import test from "node:test";
+import { settingsTestResultMessage } from "../../renderer/locales/settings-test-result-copy.js";
+
+test("missing proxy credentials have actionable bilingual copy", () => {
+  const result = {
+    ok: false,
+    code: "proxy_credential_missing",
+    message: "Proxy credential is not configured",
+  } as never;
+
+  assert.equal(
+    settingsTestResultMessage(result, "zh"),
+    "代理认证已开启,请输入代理密码后再测试。",
+  );
+  assert.equal(
+    settingsTestResultMessage(result, "en"),
+    "Proxy authentication is enabled. Enter a proxy password before testing.",
+  );
+});
diff --git a/apps/desktop/src/main/config-transfer-service.ts b/apps/desktop/src/main/config-transfer-service.ts
index a66cc53701..13c6972208 100644
--- a/apps/desktop/src/main/config-transfer-service.ts
+++ b/apps/desktop/src/main/config-transfer-service.ts
@@ -17,11 +17,12 @@
  * under the License.
  */
 
-import type { AppSettings, UpdateAppSettingsInput } from '@maka/core/settings';
+import type { UpdateAppSettingsInput } from '@maka/core/settings';
 import {
   reconcileConnectionAfterEnabledModelsChange,
   type LlmConnection,
 } from '@maka/core/llm-connections';
+import { canonicalConnectionEffectiveBaseUrl } from '@maka/core/runtime-policy';
 import {
   type ConfigBundle,
   type ConnectionConflictStrategy,
@@ -38,6 +39,10 @@ export interface ExportedCredential {
   slug: string;
   kind: CredentialKind;
   value: string;
+  connection?: {
+    providerType: LlmConnection['providerType'];
+    effectiveBaseUrl: string;
+  };
 }
 
 const VALID_CREDENTIAL_KINDS: ReadonlySet<string> = new Set<CredentialKind>([
@@ -52,9 +57,11 @@ const VALID_CREDENTIAL_KINDS: ReadonlySet<string> = new Set<CredentialKind>([
 
 export interface ConfigTransferDeps {
   connectionStore: { list(): Promise<LlmConnection[]>; save(c: LlmConnection): Promise<LlmConnection> };
-  settingsStore: { update(patch: UpdateAppSettingsInput): Promise<AppSettings> };
+  settingsStore: {
+    update(patch: UpdateAppSettingsInput): Promise<{ skippedCredentials: number }>;
+  };
   credentialStore: {
-    setSecret(slug: string, kind: CredentialKind, value: string): Promise<void>;
+    setSecret(entry: ExportedCredential): Promise<boolean>;
   };
   writeMemory(content: string): Promise<void>;
 }
@@ -72,12 +79,13 @@ export async function applyConfigImport(
   deps: ConfigTransferDeps,
 ): Promise<ConfigImportResult> {
   const result: ConfigImportResult = {};
-  // Credentials are only applied for connections actually written this import
-  // (created or overwritten). A slug the user chose to skip must not have its
-  // stored secret silently overwritten.
-  const appliedConnectionSlugs = new Set<string>();
+  // A connection snapshot limits credential writes to connections created or
+  // overwritten by this import. Credentials-only bundles instead require an
+  // existing slug whose provider and effective endpoint match the export.
+  const credentialTargets = new Map<string, LlmConnection>();
+  const hasConnectionSnapshot = Array.isArray(bundle.data.connections);
 
-  if (Array.isArray(bundle.data.connections)) {
+  if (hasConnectionSnapshot) {
     const incoming = bundle.data.connections as LlmConnection[];
     const existing = await deps.connectionStore.list();
     const plan = planConnectionMerge(existing, incoming, strategy);
@@ -91,23 +99,40 @@ export async function applyConfigImport(
         ? reconcileConnectionAfterEnabledModelsChange(connection, connection.enabledModelIds)
         : null;
       await deps.connectionStore.save(selection ? { ...connection, ...selection } : connection);
-      appliedConnectionSlugs.add(connection.slug);
+      credentialTargets.set(connection.slug, connection);
     }
     result.connections = {
       created: plan.create.length,
       overwritten: plan.overwrite.length,
       skipped: plan.skipped.length,
     };
+  } else if (
+    !bundle.includedData.includes('connections') &&
+    Array.isArray(bundle.data.credentials)
+  ) {
+    // Without a connection snapshot, the credential slug names an existing
+    // connection, while its binding proves that the slug still names the same
+    // credential destination. A bundle that does include connections still
+    // uses the create/overwrite set above so an explicit skip cannot overwrite
+    // the target's credential.
+    const existing = await deps.connectionStore.list();
+    for (const connection of existing) {
+      credentialTargets.set(connection.slug, connection);
+    }
   }
 
+  let settingsCredentialSkips = 0;
   if (bundle.data.settings && typeof bundle.data.settings === 'object') {
-    await deps.settingsStore.update(bundle.data.settings as unknown as UpdateAppSettingsInput);
+    const applied = await deps.settingsStore.update(
+      bundle.data.settings as unknown as UpdateAppSettingsInput,
+    );
+    settingsCredentialSkips = applied.skippedCredentials;
     result.settings = { applied: true };
   }
 
   if (Array.isArray(bundle.data.credentials)) {
     let applied = 0;
-    let skipped = 0;
+    let skipped = settingsCredentialSkips;
     for (const entry of bundle.data.credentials as ExportedCredential[]) {
       const valid =
         entry &&
@@ -116,17 +141,29 @@ export async function applyConfigImport(
         entry.value.length > 0 &&
         VALID_CREDENTIAL_KINDS.has(entry.kind);
       if (!valid) continue;
-      // Only write a secret for a connection that was created or overwritten
-      // in this import. Skipped (or not-imported) slugs keep their existing
-      // stored secret untouched.
-      if (!appliedConnectionSlugs.has(entry.slug)) {
+      // Unknown targets and connections explicitly skipped by a connection
+      // snapshot keep their existing stored secret untouched.
+      const target = credentialTargets.get(entry.slug);
+      if (!target) {
         skipped += 1;
         continue;
       }
-      await deps.credentialStore.setSecret(entry.slug, entry.kind, entry.value);
-      applied += 1;
+      const binding =
+        entry.connection ??
+        (hasConnectionSnapshot ? credentialConnectionBinding(target) : undefined);
+      if (!matchesCredentialConnection(binding, target)) {
+        skipped += 1;
+        continue;
+      }
+      if (await deps.credentialStore.setSecret({ ...entry, connection: binding })) {
+        applied += 1;
+      } else {
+        skipped += 1;
+      }
     }
     result.credentials = { applied, skipped };
+  } else if (settingsCredentialSkips > 0) {
+    result.credentials = { applied: 0, skipped: settingsCredentialSkips };
   }
 
   if (typeof bundle.data.memory === 'string') {
@@ -136,3 +173,31 @@ export async function applyConfigImport(
 
   return result;
 }
+
+export function matchesCredentialConnection(
+  binding: ExportedCredential['connection'] | undefined,
+  target: Pick<LlmConnection, 'providerType' | 'baseUrl'>,
+): boolean {
+  return (
+    binding !== undefined &&
+    binding.providerType === target.providerType &&
+    canonicalEndpoint(binding.effectiveBaseUrl) === canonicalConnectionEffectiveBaseUrl(target)
+  );
+}
+
+function credentialConnectionBinding(
+  connection: LlmConnection,
+): NonNullable<ExportedCredential['connection']> {
+  return {
+    providerType: connection.providerType,
+    effectiveBaseUrl: canonicalConnectionEffectiveBaseUrl(connection),
+  };
+}
+
+function canonicalEndpoint(value: string): string | null {
+  try {
+    return new URL(value).toString();
+  } catch {
+    return null;
+  }
+}
diff --git a/apps/desktop/src/main/runtime-host-boot.ts b/apps/desktop/src/main/runtime-host-boot.ts
index e57314fa05..8ac6146168 100644
--- a/apps/desktop/src/main/runtime-host-boot.ts
+++ b/apps/desktop/src/main/runtime-host-boot.ts
@@ -227,9 +227,8 @@ import { createRuntimeHostProjectCatalog } from "./runtime-host-project-catalog.
 import { createRuntimeHostDefaultRecovery } from "./runtime-host-default-recovery.js";
 import { toDesktopHostSessionSummary } from "./runtime-host-session-catalog-ipc-main.js";
 import {
-  loadRuntimeHostSettings,
+  createRuntimeHostSettingsModule,
   registerRuntimeHostSettingsIpc,
-  updateRuntimeHostSettings,
 } from "./runtime-host-settings-ipc-main.js";
 import { registerRuntimeHostSkillsIpc } from "./runtime-host-skills-ipc-main.js";
 import { registerRuntimeHostUsageIpc } from "./runtime-host-usage-ipc-main.js";
@@ -1435,29 +1434,29 @@ function registerHostClientIpc(
     openPath: (path) => shell.openPath(path),
     allowLocalPaths: !usesHostWorkspace,
   });
-  const settingsIpcDeps = {
-    ipcMain: scopedIpc,
+  const runtimeHostSettings = createRuntimeHostSettingsModule({
     client,
     settingsStore,
     applyClientSettings: async (settings) => {
       await clientSettingsEffects.apply(settings, true);
     },
-  } satisfies Parameters<typeof registerRuntimeHostSettingsIpc>[0];
-  registerRuntimeHostSettingsIpc(settingsIpcDeps);
+  });
+  registerRuntimeHostSettingsIpc({
+    ipcMain: scopedIpc,
+    module: runtimeHostSettings,
+  });
   registerRuntimeHostConfigIpc({
     ipcMain: scopedIpc,
     client,
     mainWindowController,
     appVersion: app.getVersion(),
-    getSettings: () => loadRuntimeHostSettings(settingsIpcDeps),
-    updateSettings: (patch) =>
-      updateRuntimeHostSettings(settingsIpcDeps, patch),
+    settingsModule: runtimeHostSettings,
     emitConnectionsChanged: emitTargetConnectionListChanged,
   });
   registerRuntimeHostPermissionsIpc({
     ipcMain: scopedIpc,
     client,
-    getSettings: () => loadRuntimeHostSettings(settingsIpcDeps),
+    getSettings: () => runtimeHostSettings.get(),
     listConnections: async () =>
       projectHostConnections(await client.loadConnectionCatalog()),
     botRegistry,
@@ -1496,7 +1495,7 @@ function registerHostClientIpc(
       return selectedDesktopWorkspaceTarget(target);
     },
     getDefaultPermissionMode: () =>
-      resolveDefaultPermissionMode(() => loadRuntimeHostSettings(settingsIpcDeps)),
+      resolveDefaultPermissionMode(() => runtimeHostSettings.get()),
     openPath: (path) => shell.openPath(path),
     allowLocalPaths: !usesHostWorkspace,
   });
diff --git a/apps/desktop/src/main/runtime-host-client.ts b/apps/desktop/src/main/runtime-host-client.ts
index 29b98597c5..f30d31475b 100644
--- a/apps/desktop/src/main/runtime-host-client.ts
+++ b/apps/desktop/src/main/runtime-host-client.ts
@@ -427,6 +427,12 @@ export class DesktopRuntimeHostClient {
     throw revisionConflict("Runtime Policy update", "workspace");
   }
 
+  updateNetworkProxy(
+    input: OperationInput<"runtime.policy.network-proxy.update">,
+  ): Promise<OperationOutput<"runtime.policy.network-proxy.update">> {
+    return this.request("runtime.policy.network-proxy.update", input);
+  }
+
   queryMemory(input: MemoryQueryInput): Promise<MemoryQueryResult> {
     return this.request("memory.query", input);
   }
diff --git a/apps/desktop/src/main/runtime-host-config-ipc-main.ts b/apps/desktop/src/main/runtime-host-config-ipc-main.ts
index 51d002c19b..073283c34b 100644
--- a/apps/desktop/src/main/runtime-host-config-ipc-main.ts
+++ b/apps/desktop/src/main/runtime-host-config-ipc-main.ts
@@ -18,16 +18,24 @@
  */
 
 import { readFile, writeFile } from 'node:fs/promises';
+import { isDeepStrictEqual } from 'node:util';
 import type { IpcMain } from 'electron';
 import type { AppSettings, UpdateAppSettingsInput } from '@maka/core/settings';
 import type { LlmConnection } from '@maka/core/llm-connections';
 import { PROVIDER_REGISTRY } from '@maka/core/llm-connections';
-import type {
-  ConnectionCatalogEntry,
-  CredentialLocator,
+import {
+  canonicalConnectionEffectiveBaseUrl,
+  connectionCredentialTarget,
+  type ConnectionCatalogEntry,
+  type ConnectionCredentialTarget,
+  type CredentialLocator,
+  type NetworkProxyCredentialTarget,
+  normalizeNetworkProxyCredentialTarget,
 } from '@maka/core/runtime-policy';
+import { networkProxyCredentialTarget } from '@maka/core/settings';
 import {
   applyConfigImport,
+  matchesCredentialConnection,
   type ConfigTransferDeps,
   type ExportedCredential,
 } from './config-transfer-service.js';
@@ -43,12 +51,17 @@ import {
 import {
   stripSettingsSecretsForExport,
 } from './settings-ipc-helpers.js';
+import {
+  runRuntimeHostSettingsExclusive,
+  type RuntimeHostSettingsModule,
+} from './runtime-host-settings-ipc-main.js';
 import {
   buildConfigBundle,
   isConfigCategory,
   parseConfigBundle,
   serializeConfigBundle,
   type ConfigCategory,
+  type ConfigBundle,
   type ConfigData,
   type ConnectionConflictStrategy,
 } from '@maka/storage/config-transfer';
@@ -58,11 +71,21 @@ interface RuntimeHostConfigIpcDeps {
   readonly client: DesktopRuntimeHostClient;
   readonly mainWindowController: ReturnType<typeof createMainWindowController>;
   readonly appVersion: string;
+  readonly settingsModule: RuntimeHostSettingsModule;
+  readonly emitConnectionsChanged: () => void;
+}
+
+interface RuntimeHostConfigGatherDeps {
+  readonly client: DesktopRuntimeHostClient;
+  readonly appVersion: string;
   readonly getSettings: () => Promise<AppSettings>;
-  readonly updateSettings: (
+}
+
+interface RuntimeHostConfigTransferDeps {
+  readonly client: DesktopRuntimeHostClient;
+  readonly updateSettingsForConfigImport: (
     patch: UpdateAppSettingsInput,
-  ) => Promise<AppSettings>;
-  readonly emitConnectionsChanged: () => void;
+  ) => Promise<{ skippedCredentials: number }>;
 }
 
 export function registerRuntimeHostConfigIpc(
@@ -75,7 +98,6 @@ export function registerRuntimeHostConfigIpc(
       if (categories.length === 0) {
         return { ok: false as const, reason: 'no_categories' as const };
       }
-      const bundle = await gatherRuntimeHostConfig(categories, deps);
       const today = new Date().toISOString().slice(0, 10);
       const result = await deps.mainWindowController.showSaveDialog({
         title: '导出 Maka 配置',
@@ -85,6 +107,15 @@ export function registerRuntimeHostConfigIpc(
       if (result.canceled || !result.filePath) {
         return { ok: false as const, reason: 'canceled' as const };
       }
+      const bundle = await runRuntimeHostSettingsExclusive(
+        deps.settingsModule,
+        (settings) =>
+          gatherRuntimeHostConfig(categories, {
+            client: deps.client,
+            appVersion: deps.appVersion,
+            getSettings: settings.get,
+          }),
+      );
       await writeFile(result.filePath, serializeConfigBundle(bundle), 'utf8');
       return {
         ok: true as const,
@@ -114,10 +145,29 @@ export function registerRuntimeHostConfigIpc(
           message: parsed.message,
         };
       }
-      const imported = await applyConfigImport(
-        parsed.bundle,
-        sanitizeStrategy(input?.strategy),
-        runtimeHostTransferDeps(deps),
+      let importBundle: ConfigBundle;
+      try {
+        importBundle = adaptRuntimeHostConfigImport(parsed.bundle);
+      } catch (error) {
+        return {
+          ok: false as const,
+          reason: 'malformed' as const,
+          message: error instanceof Error ? error.message : 'Invalid settings payload.',
+        };
+      }
+      const imported = await runRuntimeHostSettingsExclusive(
+        deps.settingsModule,
+        (settings) =>
+          applyConfigImport(
+            importBundle,
+            sanitizeStrategy(input?.strategy),
+            runtimeHostTransferDeps(
+              {
+                client: deps.client,
+                updateSettingsForConfigImport: settings.updateForConfigImport,
+              },
+            ),
+          ),
       );
       deps.emitConnectionsChanged();
       return {
@@ -131,18 +181,51 @@ export function registerRuntimeHostConfigIpc(
 
 export async function gatherRuntimeHostConfig(
   categories: readonly ConfigCategory[],
-  deps: RuntimeHostConfigIpcDeps,
+  deps: RuntimeHostConfigGatherDeps,
 ) {
   const selected = new Set(categories);
   const data: ConfigData = {};
-  const catalog =
-    selected.has('connections') || selected.has('credentials')
-      ? await deps.client.loadConnectionCatalog()
-      : undefined;
-  const locators = selected.has('credentials')
-    ? exportLocators(catalog?.connections ?? [])
-    : [];
-  const exported = await exportConfigurationCredentials(deps.client, locators);
+  let catalog = selected.has('connections') && !selected.has('credentials')
+    ? await deps.client.loadConnectionCatalog()
+    : undefined;
+  let exported: Awaited<ReturnType<typeof exportConfigurationCredentials>> = {
+    credentials: [],
+    connectionStale: false,
+    proxyTarget: undefined,
+  };
+  let settings: AppSettings | undefined;
+  if (selected.has('credentials')) {
+    for (let attempt = 0; attempt < 3; attempt += 1) {
+      catalog = await deps.client.loadConnectionCatalog();
+      exported = await exportConfigurationCredentials(
+        deps.client,
+        exportLocators(catalog.connections),
+      );
+      if (exported.connectionStale) {
+        if (attempt === 2) {
+          throw new Error('Connection targets kept changing while credentials were exported');
+        }
+        continue;
+      }
+      if (
+        selected.has('settings') &&
+        exported.proxyTarget &&
+        !isDeepStrictEqual(
+          exported.proxyTarget,
+          networkProxyCredentialTarget((settings = await deps.getSettings()).network.proxy),
+        )
+      ) {
+        if (attempt === 2) {
+          throw new Error('Proxy target kept changing while credentials were exported');
+        }
+        continue;
+      }
+      if (selected.has('settings') && !settings) settings = await deps.getSettings();
+      break;
+    }
+  } else if (selected.has('settings')) {
+    settings = await deps.getSettings();
+  }
   const secrets = new Map(
     exported.credentials.map((entry) => [locatorKey(entry.locator), entry.secret]),
   );
@@ -150,11 +233,17 @@ export async function gatherRuntimeHostConfig(
   if (selected.has('connections') && catalog) {
     data.connections = projectHostConnections(catalog);
   }
+  // Schema v1 stores the network-proxy password and Tavily key in the
+  // settings payload. Keep a credentials-only request lossless by making the
+  // dependency explicit in the generated bundle.
   if (selected.has('settings')) {
-    const settings = await deps.getSettings();
+    if (!settings) throw new Error('Settings snapshot was not gathered');
     data.settings = selected.has('credentials')
       ? restoreHostSettingsSecrets(settings, secrets)
       : stripSettingsSecretsForExport(settings);
+  } else if (selected.has('credentials')) {
+    const settingsSecrets = projectHostSettingsSecrets(exported.proxyTarget, secrets);
+    if (settingsSecrets) data.settings = settingsSecrets;
   }
   if (selected.has('credentials') && catalog) {
     data.credentials = connectionCredentials(catalog.connections, secrets);
@@ -167,23 +256,48 @@ export async function gatherRuntimeHostConfig(
 
 async function exportConfigurationCredentials(
   client: DesktopRuntimeHostClient,
-  locators: readonly CredentialLocator[],
+  requests: readonly CredentialExportRequest[],
 ) {
-  const credentials: Array<{ locator: CredentialLocator; secret: string }> = [];
-  for (const locator of locators) {
-    const exported = await client.exportConfigurationCredentials({ locator });
+  const credentials: Array<{
+    locator: CredentialLocator;
+    secret: string;
+    proxyTarget?: NetworkProxyCredentialTarget;
+  }> = [];
+  let proxyTarget: NetworkProxyCredentialTarget | undefined;
+  for (const request of requests) {
+    const exported = await client.exportConfigurationCredentials(request);
+    if (exported.connectionStale) {
+      return { credentials: [], connectionStale: true, proxyTarget: undefined };
+    }
     if (exported.credential) {
+      if (
+        exported.credential.locator.scope === 'network_proxy' &&
+        !exported.credential.proxyTarget
+      ) {
+        throw new Error('Runtime Host omitted the proxy credential target binding');
+      }
+      if (exported.credential.proxyTarget) {
+        proxyTarget = exported.credential.proxyTarget;
+      }
       credentials.push({
         locator: exported.credential.locator,
         secret: Buffer.from(exported.credential.secretBase64, 'base64').toString('utf8'),
+        ...(exported.credential.proxyTarget === undefined
+          ? {}
+          : { proxyTarget: exported.credential.proxyTarget }),
       });
     }
   }
-  return { credentials };
+  return { credentials, connectionStale: false, proxyTarget };
+}
+
+interface CredentialExportRequest {
+  readonly locator: CredentialLocator;
+  readonly expectedConnection?: ConnectionCredentialTarget;
 }
 
 function runtimeHostTransferDeps(
-  deps: RuntimeHostConfigIpcDeps,
+  deps: RuntimeHostConfigTransferDeps,
 ): ConfigTransferDeps {
   return {
     connectionStore: {
@@ -192,11 +306,13 @@ function runtimeHostTransferDeps(
       save: (connection) => saveConnection(deps.client, connection),
     },
     settingsStore: {
-      update: deps.updateSettings,
+      update: async (patch) => {
+        const result = await deps.updateSettingsForConfigImport(patch);
+        return { skippedCredentials: result.skippedCredentials };
+      },
     },
     credentialStore: {
-      setSecret: (slug, kind, value) =>
-        saveConnectionCredential(deps.client, slug, kind, value),
+      setSecret: (entry) => saveConnectionCredential(deps.client, entry),
     },
     writeMemory: (content) =>
       replaceRuntimeHostMemoryDocument(deps.client, content),
@@ -267,38 +383,35 @@ export async function saveConnection(
 
 async function saveConnectionCredential(
   client: DesktopRuntimeHostClient,
-  slug: string,
-  kind: string,
-  value: string,
-): Promise<void> {
+  entry: ExportedCredential,
+): Promise<boolean> {
   const catalog = await client.loadConnectionCatalog();
-  const connection = catalog.connections.find((item) => item.slug === slug);
-  if (!connection) throw new Error(`Imported Connection not found: ${slug}`);
+  const connection = catalog.connections.find((item) => item.slug === entry.slug);
+  if (!connection || !matchesCredentialConnection(entry.connection, connection)) return false;
   const locator =
-    kind === 'request_headers'
+    entry.kind === 'request_headers'
       ? ({
           scope: 'connection',
           connectionId: connection.connectionId,
           kind: 'request_headers',
         } as const)
       : connectionCredentialLocator(connection);
-  if (!locator || locator.kind !== kind) return;
+  if (!locator || locator.kind !== entry.kind) return false;
   const current = await client.queryCredential(locator);
   const saved = await client.setCredential({
     locator,
     expected: current?.configured
       ? { credentialId: current.credentialId, revision: current.revision }
       : null,
-    secret: value,
+    expectedConnection: connectionCredentialTarget(connection),
+    secret: entry.value,
   });
-  if (saved.kind !== 'committed') {
-    throw new Error(`Unable to save imported Connection credential: ${saved.kind}`);
-  }
+  return saved.kind === 'committed';
 }
 
 function exportLocators(
   connections: readonly ConnectionCatalogEntry[],
-): CredentialLocator[] {
+): CredentialExportRequest[] {
   return [
     ...connections.flatMap((connection) => {
       const locator = connectionCredentialLocator(connection);
@@ -307,10 +420,16 @@ function exportLocators(
         connectionId: connection.connectionId,
         kind: 'request_headers',
       } as const;
-      return locator ? [locator, requestHeaders] : [requestHeaders];
+      const expectedConnection = connectionCredentialTarget(connection);
+      return (locator ? [locator, requestHeaders] : [requestHeaders]).map(
+        (connectionLocator) => ({
+          locator: connectionLocator,
+          expectedConnection,
+        }),
+      );
     }),
-    { scope: 'network_proxy', kind: 'password' },
-    { scope: 'web_search', provider: 'tavily', kind: 'api_key' },
+    { locator: { scope: 'network_proxy', kind: 'password' } },
+    { locator: { scope: 'web_search', provider: 'tavily', kind: 'api_key' } },
   ];
 }
 
@@ -328,27 +447,54 @@ function connectionCredentials(
     } as const;
     const requestHeaders = secrets.get(locatorKey(requestHeadersLocator));
     return [
-      ...(locator && secret ? [{ slug: connection.slug, kind: locator.kind, value: secret }] : []),
+      ...(locator && secret
+        ? [{
+            slug: connection.slug,
+            kind: locator.kind,
+            value: secret,
+            connection: credentialConnectionBinding(connection),
+          }]
+        : []),
       ...(requestHeaders
-        ? [{ slug: connection.slug, kind: 'request_headers' as const, value: requestHeaders }]
+        ? [{
+            slug: connection.slug,
+            kind: 'request_headers' as const,
+            value: requestHeaders,
+            connection: credentialConnectionBinding(connection),
+          }]
         : []),
     ];
   });
 }
 
+function credentialConnectionBinding(
+  connection: ConnectionCatalogEntry,
+): NonNullable<ExportedCredential['connection']> {
+  return {
+    providerType: connection.providerType,
+    effectiveBaseUrl: canonicalConnectionEffectiveBaseUrl(connection),
+  };
+}
+
 function restoreHostSettingsSecrets(
   settings: AppSettings,
   secrets: ReadonlyMap<string, string>,
-): AppSettings {
+): Record<string, unknown> {
   const proxy = secrets.get(locatorKey({ scope: 'network_proxy', kind: 'password' })) ?? '';
   const webSearch =
     secrets.get(
       locatorKey({ scope: 'web_search', provider: 'tavily', kind: 'api_key' }),
     ) ?? '';
+  const {
+    passwordConfigured: _passwordConfigured,
+    ...proxySettings
+  } = settings.network.proxy as typeof settings.network.proxy & {
+    passwordConfigured?: boolean;
+  };
   return {
     ...settings,
     network: {
-      proxy: { ...settings.network.proxy, password: proxy },
+      proxy: { ...proxySettings, password: proxy },
     },
     webSearch: {
       ...settings.webSearch,
@@ -362,6 +508,130 @@ function restoreHostSettingsSecrets(
   };
 }
 
+function projectHostSettingsSecrets(
+  proxyTarget: NetworkProxyCredentialTarget | undefined,
+  secrets: ReadonlyMap<string, string>,
+): Record<string, unknown> | undefined {
+  const proxy = secrets.get(
+    locatorKey({ scope: 'network_proxy', kind: 'password' }),
+  );
+  const tavily = secrets.get(
+    locatorKey({ scope: 'web_search', provider: 'tavily', kind: 'api_key' }),
+  );
+  if (proxy === undefined && tavily === undefined) return undefined;
+
+  return {
+    ...(proxy === undefined || proxyTarget === undefined
+      ? {}
+      : {
+          network: {
+            proxy: {
+              password: proxy,
+              credentialTarget: proxyTarget,
+            },
+          },
+        }),
+    ...(tavily === undefined
+      ? {}
+      : {
+          webSearch: {
+            providers: {
+              tavily: { apiKey: tavily },
+            },
+          },
+        }),
+  };
+}
+
+/** Convert schema-v1 wire secrets into the write-only Runtime Host contract. */
+export function adaptRuntimeHostConfigImport(bundle: ConfigBundle): ConfigBundle {
+  const settings = bundle.data.settings;
+  if (!isRecord(settings)) return bundle;
+  const network = settings.network;
+  if (!isRecord(network) || !isRecord(network.proxy)) return bundle;
+
+  const wireProxy = network.proxy;
+  const credentialTarget = wireProxy.credentialTarget;
+  const passwordPresent = Object.prototype.hasOwnProperty.call(
+    wireProxy,
+    'password',
+  );
+  const password = wireProxy.password;
+  const includesCredentials = bundle.includedData.includes('credentials');
+  if (
+    includesCredentials &&
+    passwordPresent &&
+    typeof password !== 'string'
+  ) {
+    throw new Error('Proxy password in imported settings must be a string.');
+  }
+  if (
+    includesCredentials &&
+    typeof password === 'string' &&
+    password.length > 0 &&
+    wireProxy.authEnabled === false
+  ) {
+    throw new Error(
+      'Cannot import a proxy password while proxy authentication is disabled.',
+    );
+  }
+  if (
+    includesCredentials &&
+    typeof password === 'string' &&
+    password.length > 0 &&
+    credentialTarget === undefined
+  ) {
+    throw new Error('Proxy password import requires a target binding.');
+  }
+
+  const {
+    password: _password,
+    passwordConfigured: _passwordConfigured,
+    credential: _credential,
+    credentialTarget: _credentialTarget,
+    ...ordinaryProxy
+  } = wireProxy;
+  const proxy = {
+    ...ordinaryProxy,
+    ...(includesCredentials && passwordPresent
+      ? {
+          credential:
+            (password as string).length === 0
+              ? ({ kind: 'delete' } as const)
+              : ({
+                  kind: 'replace',
+                  secret: password as string,
+                  ...(credentialTarget === undefined
+                    ? {}
+                    : {
+                        expectedTarget: normalizeNetworkProxyCredentialTarget(
+                          credentialTarget,
+                        ),
+                      }),
+                } as const),
+        }
+      : {}),
+  };
+
+  return {
+    ...bundle,
+    data: {
+      ...bundle.data,
+      settings: {
+        ...settings,
+        network: {
+          ...network,
+          proxy,
+        },
+      },
+    },
+  };
+}
+
+function isRecord(value: unknown): value is Record<string, unknown> {
+  return typeof value === 'object' && value !== null && !Array.isArray(value);
+}
+
 function connectionCredentialLocator(
   connection: ConnectionCatalogEntry,
 ): Extract<CredentialLocator, { scope: 'connection' }> | null {
diff --git a/apps/desktop/src/main/runtime-host-settings-ipc-main.ts b/apps/desktop/src/main/runtime-host-settings-ipc-main.ts
index f7b6065941..369ec810e0 100644
--- a/apps/desktop/src/main/runtime-host-settings-ipc-main.ts
+++ b/apps/desktop/src/main/runtime-host-settings-ipc-main.ts
@@ -19,6 +19,7 @@
 
 import type {
   AppSettings,
+  RuntimeHostAppSettings,
   SettingsTestResult,
   UpdateAppSettingsInput,
   UpdateAppSettingsResult,
@@ -56,6 +57,7 @@ type RuntimeHostSettingsClient = Pick<
   | "queryRuntimePolicy"
   | "setCredential"
   | "testNetworkProxy"
+  | "updateNetworkProxy"
   | "updateRuntimePolicy"
 >;
 
@@ -76,85 +78,130 @@ export interface RuntimeHostSettingsIpcDeps {
   readonly applyClientSettings: (settings: AppSettings) => Promise<void>;
 }
 
+export type RuntimeHostSettingsModuleDeps = Omit<
+  RuntimeHostSettingsIpcDeps,
+  "ipcMain"
+>;
+
+export interface RuntimeHostSettingsModule {
+  get(): Promise<RuntimeHostAppSettings>;
+  update(patch: UpdateAppSettingsInput): Promise<RuntimeHostAppSettings>;
+  testNetworkProxy(input?: TestProxyInput): Promise<SettingsTestResult>;
+}
+
+export interface RuntimeHostSettingsExclusiveAccess {
+  get(): Promise<RuntimeHostAppSettings>;
+  update(patch: UpdateAppSettingsInput): Promise<RuntimeHostAppSettings>;
+  updateForConfigImport(
+    patch: UpdateAppSettingsInput,
+  ): Promise<RuntimeHostSettingsImportResult>;
+}
+
+export interface RuntimeHostSettingsImportResult {
+  readonly settings: RuntimeHostAppSettings;
+  readonly skippedCredentials: number;
+}
+
+type RuntimeHostSettingsExclusiveRunner = <T>(
+  operation: (access: RuntimeHostSettingsExclusiveAccess) => Promise<T>,
+) => Promise<T>;
+
+const exclusiveRunners = new WeakMap<
+  RuntimeHostSettingsModule,
+  RuntimeHostSettingsExclusiveRunner
+>();
+
+interface RuntimeHostSettingsIpcRegistrationDeps {
+  readonly ipcMain: ReconnectableReadIpcMain;
+  readonly module: RuntimeHostSettingsModule;
+}
+
+export function createRuntimeHostSettingsModule(
+  deps: RuntimeHostSettingsModuleDeps,
+): RuntimeHostSettingsModule {
+  let lane: Promise<void> = Promise.resolve();
+
+  function enqueue<T>(operation: () => Promise<T>): Promise<T> {
+    const result = lane.then(operation, operation);
+    lane = result.then(
+      () => undefined,
+      () => undefined,
+    );
+    return result;
+  }
+
+  const module: RuntimeHostSettingsModule = {
+    get: () => enqueue(() => loadRuntimeHostSettingsWithoutLane(deps)),
+    update: (patch) =>
+      enqueue(() =>
+        updateRuntimeHostSettingsForImportWithoutLane(deps, patch).then(
+          (result) => result.settings,
+        ),
+      ),
+    testNetworkProxy: (input = {}) =>
+      enqueue(() => testNetworkProxyWithoutLane(deps.client, input)),
+  };
+  exclusiveRunners.set(module, (operation) =>
+    enqueue(() =>
+      operation({
+        get: () => loadRuntimeHostSettingsWithoutLane(deps),
+        update: (patch) =>
+          updateRuntimeHostSettingsForImportWithoutLane(deps, patch).then(
+            (result) => result.settings,
+          ),
+        updateForConfigImport: (patch) =>
+          updateRuntimeHostSettingsForImportWithoutLane(deps, patch),
+      }),
+    ),
+  );
+  return module;
+}
+
+/**
+ * Runs a compound Settings adapter operation in this Runtime Host's lane.
+ * The supplied accessors deliberately bypass re-entry into the public queue.
+ */
+export function runRuntimeHostSettingsExclusive<T>(
+  module: RuntimeHostSettingsModule,
+  operation: (access: RuntimeHostSettingsExclusiveAccess) => Promise<T>,
+): Promise<T> {
+  const run = exclusiveRunners.get(module);
+  if (!run) {
+    throw new Error('Runtime Host Settings module does not own an exclusive lane');
+  }
+  return run(operation);
+}
+
 export function registerRuntimeHostSettingsIpc(
-  deps: RuntimeHostSettingsIpcDeps,
+  deps: RuntimeHostSettingsIpcRegistrationDeps,
 ): void {
+  const module = deps.module;
   handleReconnectableRead(deps.ipcMain, "settings:get", async () =>
-    maskAppSettings(await loadRuntimeHostSettings(deps)),
+    maskAppSettings(await module.get()),
   );
   deps.ipcMain.handle(
     "settings:testNetworkProxy",
-    async (_event, input: TestProxyInput = {}) => {
-      const current = (await deps.client.queryRuntimePolicy()).policy
-        .networkProxy;
-      const candidate = input.proxy
-        ? toRuntimeHostProxyPolicy(input.proxy, current.autoBypassDomains)
-        : undefined;
-      const password = credentialOverride(input.proxy?.password);
-      const result = await deps.client.testNetworkProxy({
-        ...(candidate ? { networkProxy: candidate } : {}),
-        ...(password ? { password } : {}),
-        ...(input.url ? { url: input.url } : {}),
-        ...(input.timeoutMs ? { timeoutMs: input.timeoutMs } : {}),
-      });
-      const tested = candidate ?? current;
-      if (!result.ok) {
-        const failure = proxyTestFailure(result);
-        return {
-          ok: false,
-          ...failure,
-          latencyMs: result.latencyMs,
-          details: { status: result.status },
-        } satisfies SettingsTestResult;
-      }
-      return {
-        ok: true,
-        code: "proxy_reachable",
-        message: `The proxy ${tested.protocol}://${tested.host}:${tested.port} is reachable.`,
-        latencyMs: result.latencyMs,
-        details: {
-          endpoint: `${tested.protocol}://${tested.host}:${tested.port}`,
-          status: result.status,
-          ip: result.ip,
-          countryCode: result.countryCode,
-          countryFlag: result.countryFlag,
-          bypassList: tested.bypassList,
-        },
-      } satisfies SettingsTestResult;
-    },
+    async (_event, input: TestProxyInput = {}) => module.testNetworkProxy(input),
   );
   deps.ipcMain.handle(
     "settings:update",
     async (
       _event,
       patch: UpdateAppSettingsInput,
-    ): Promise<UpdateAppSettingsResult> => {
-      const settings = await updateRuntimeHostSettings(deps, patch);
+    ): Promise<UpdateAppSettingsResult<RuntimeHostAppSettings>> => {
+      const settings = await module.update(patch);
       return buildSettingsUpdateResult(settings, patch);
     },
   );
 }
 
-export async function updateRuntimeHostSettings(
-  deps: RuntimeHostSettingsIpcDeps,
-  patch: UpdateAppSettingsInput,
-): Promise<AppSettings> {
-  await applyHostPatch(deps.client, patch);
-  const clientPatch = clientOwnedSettingsPatch(patch);
-  const local = hasSettingsPatch(clientPatch)
-    ? await deps.settingsStore.update(clientPatch)
-    : await deps.settingsStore.get();
-  await deps.applyClientSettings(local);
-  return loadRuntimeHostSettings(deps);
-}
-
 function toRuntimeHostProxyPolicy(
   proxy: TestProxySettings,
   autoBypassDomains: readonly string[],
 ): RuntimePolicy["networkProxy"] {
   const username = proxy.username?.trim() ?? "";
   const authEnabled =
-    proxy.authEnabled ?? Boolean(username || proxy.password);
+    proxy.authEnabled ?? Boolean(username);
   return {
     enabled: proxy.enabled,
     protocol: proxy.type,
@@ -167,13 +214,48 @@ function toRuntimeHostProxyPolicy(
   };
 }
 
-function credentialOverride(value: string | undefined): string | undefined {
-  return !value || value === SENSITIVE_PLACEHOLDER ? undefined : value;
+async function testNetworkProxyWithoutLane(
+  client: RuntimeHostSettingsClient,
+  input: TestProxyInput,
+): Promise<SettingsTestResult> {
+  const current = (await client.queryRuntimePolicy()).policy.networkProxy;
+  const candidate = input.proxy
+    ? toRuntimeHostProxyPolicy(input.proxy, current.autoBypassDomains)
+    : undefined;
+  const result = await client.testNetworkProxy({
+    ...(candidate ? { networkProxy: candidate } : {}),
+    ...(input.url ? { url: input.url } : {}),
+    ...(input.timeoutMs ? { timeoutMs: input.timeoutMs } : {}),
+  });
+  const tested = candidate ?? current;
+  if (!result.ok) {
+    const failure = proxyTestFailure(result);
+    return {
+      ok: false,
+      ...failure,
+      latencyMs: result.latencyMs,
+      details: { status: result.status },
+    };
+  }
+  return {
+    ok: true,
+    code: "proxy_reachable",
+    message: `The proxy ${tested.protocol}://${tested.host}:${tested.port} is reachable.`,
+    latencyMs: result.latencyMs,
+    details: {
+      endpoint: `${tested.protocol}://${tested.host}:${tested.port}`,
+      status: result.status,
+      ip: result.ip,
+      countryCode: result.countryCode,
+      countryFlag: result.countryFlag,
+      bypassList: tested.bypassList,
+    },
+  };
 }
 
-export async function loadRuntimeHostSettings(
-  deps: RuntimeHostSettingsIpcDeps,
-): Promise<AppSettings> {
+async function loadRuntimeHostSettingsWithoutLane(
+  deps: RuntimeHostSettingsModuleDeps,
+): Promise<RuntimeHostAppSettings> {
   const [local, runtimePolicy, proxyCredential, webSearchCredential] =
     await Promise.all([
       deps.settingsStore.get(),
@@ -189,7 +271,7 @@ export async function loadRuntimeHostSettings(
         ...policy.networkProxy,
         bypassList: [...policy.networkProxy.bypassList],
         autoBypassDomains: [...policy.networkProxy.autoBypassDomains],
-        password: proxyCredential?.configured ? SENSITIVE_PLACEHOLDER : "",
+        passwordConfigured: proxyCredential?.configured === true,
       },
     },
     personalization: {
@@ -212,6 +294,23 @@ export async function loadRuntimeHostSettings(
   };
 }
 
+async function updateRuntimeHostSettingsForImportWithoutLane(
+  deps: RuntimeHostSettingsModuleDeps,
+  patch: UpdateAppSettingsInput,
+): Promise<RuntimeHostSettingsImportResult> {
+  validateProxyPatch(patch.network?.proxy);
+  const skippedCredentials = await applyHostPatchWithoutLane(deps.client, patch);
+  const clientPatch = clientOwnedSettingsPatch(patch);
+  const local = hasSettingsPatch(clientPatch)
+    ? await deps.settingsStore.update(clientPatch)
+    : await deps.settingsStore.get();
+  await deps.applyClientSettings(local);
+  return {
+    settings: await loadRuntimeHostSettingsWithoutLane(deps),
+    skippedCredentials,
+  };
+}
+
 function projectWebSearchCredential(
   local: AppSettings,
   credential: CredentialStatus | null,
@@ -234,26 +333,13 @@ function projectWebSearchCredential(
   };
 }
 
-async function applyHostPatch(
+async function applyHostPatchWithoutLane(
   client: RuntimeHostSettingsClient,
   patch: UpdateAppSettingsInput,
-): Promise<void> {
+): Promise<number> {
+  let skippedCredentials = 0;
   if (patch.network?.proxy) {
-    const proxy = patch.network.proxy;
-    await client.updateRuntimePolicy((policy) => ({
-      kind: "set_network_proxy",
-      value: { ...policy.networkProxy, ...withoutSecret(proxy) },
-    }));
-    if (proxy.authEnabled === false)
-      await deleteCredential(client, PROXY_CREDENTIAL);
-    else if (
-      proxy.password !== undefined &&
-      proxy.password !== SENSITIVE_PLACEHOLDER
-    ) {
-      if (proxy.password.length === 0)
-        await deleteCredential(client, PROXY_CREDENTIAL);
-      else await setCredential(client, PROXY_CREDENTIAL, proxy.password);
-    }
+    skippedCredentials += await updateNetworkProxy(client, patch.network.proxy);
   }
   if (
     patch.personalization?.displayName !== undefined ||
@@ -324,6 +410,45 @@ async function applyHostPatch(
       value: patch.subagents!,
     }));
   }
+  return skippedCredentials;
+}
+
+async function updateNetworkProxy(
+  client: RuntimeHostSettingsClient,
+  patch: NonNullable<NonNullable<UpdateAppSettingsInput["network"]>["proxy"]>,
+): Promise<number> {
+  const [policy, credential] = await Promise.all([
+    client.queryRuntimePolicy(),
+    client.queryCredential(PROXY_CREDENTIAL),
+  ]);
+  const networkProxy = {
+    ...policy.policy.networkProxy,
+    ...withoutCredential(patch),
+  };
+  const operation =
+    patch.credential?.kind === "replace"
+      ? patch.credential
+      : !networkProxy.authEnabled || patch.credential?.kind === "delete"
+        ? ({ kind: "delete" } as const)
+        : ({ kind: "keep" } as const);
+  const result = await client.updateNetworkProxy({
+    expectedPolicyRevision: policy.revision,
+    expectedCredential: credential?.configured
+      ? {
+          locator: credential.locator,
+          credentialId: credential.credentialId,
+          revision: credential.revision,
+        }
+      : null,
+    networkProxy,
+    credential: operation,
+  });
+  if (result.kind === "committed") return 0;
+  if (result.kind === "proxy_target_mismatch") return 1;
+  if (result.kind === "revision_conflict") {
+    throw new Error("Runtime Host proxy policy changed while Desktop updated it");
+  }
+  throw new Error("Runtime Host proxy credential changed while Desktop updated it");
 }
 
 async function mergePolicy<
@@ -391,9 +516,38 @@ async function deleteCredential(
   throw new Error("Credential kept changing while Desktop removed it");
 }
 
-function withoutSecret(
+function withoutCredential(
   patch: NonNullable<NonNullable<UpdateAppSettingsInput["network"]>["proxy"]>,
 ): Partial<RuntimePolicy["networkProxy"]> {
-  const { password: _password, ...value } = patch;
+  const {
+    credential: _credential,
+    password: _legacyPassword,
+    passwordConfigured: _derivedStatus,
+    ...value
+  } = patch as typeof patch & {
+    password?: unknown;
+    passwordConfigured?: unknown;
+  };
   return value;
 }
+
+function validateProxyPatch(
+  proxy: NonNullable<UpdateAppSettingsInput["network"]>["proxy"] | undefined,
+): void {
+  const operation = proxy?.credential;
+  if (!operation) return;
+  if (operation.kind === "replace") {
+    if (typeof operation.secret !== "string" || operation.secret.length === 0) {
+      throw new Error("Proxy credential replacement requires a non-empty password");
+    }
+    if (proxy.authEnabled === false) {
+      throw new Error(
+        "Cannot replace the proxy credential while authentication is disabled",
+      );
+    }
+    return;
+  }
+  if (operation.kind !== "delete") {
+    throw new Error("Unsupported proxy credential operation");
+  }
+}
diff --git a/apps/desktop/src/main/settings-ipc-helpers.ts b/apps/desktop/src/main/settings-ipc-helpers.ts
index 2404d1463f..df8952d38b 100644
--- a/apps/desktop/src/main/settings-ipc-helpers.ts
+++ b/apps/desktop/src/main/settings-ipc-helpers.ts
@@ -19,6 +19,7 @@
 
 import type {
   AppSettings,
+  RuntimeHostAppSettings,
   SettingsTestResult,
   SettingsTestResultCode,
   UpdateAppSettingsInput,
@@ -50,6 +51,11 @@ export function proxyTestFailure(result: TestProxyResult): {
       code: "proxy_configuration_missing",
       message: "The proxy host or port is missing.",
     };
+  if (lower.includes("proxy credential is not configured"))
+    return {
+      code: "proxy_credential_missing",
+      message: "The proxy credential is not configured.",
+    };
   if (lower.includes("proxy test timeout") || lower.includes("timeout"))
     return { code: "proxy_timeout", message: "The proxy test timed out." };
   if (result.status)
@@ -64,72 +70,20 @@ export function proxyTestFailure(result: TestProxyResult): {
   };
 }
 
-export function preserveSensitivePlaceholders(
-  patch: UpdateAppSettingsInput,
-  current: AppSettings,
-): UpdateAppSettingsInput {
-  const botChannels = patch.botChat?.channels
-    ? Object.fromEntries(
-        Object.entries(patch.botChat.channels).map(
-          ([provider, channelPatch]) => {
-            const currentChannel =
-              current.botChat.channels[provider as BotProvider];
-            return [
-              provider,
-              {
-                ...channelPatch,
-                ...(channelPatch?.token === SENSITIVE_PLACEHOLDER
-                  ? { token: currentChannel.token }
-                  : {}),
-                ...(channelPatch?.appSecret === SENSITIVE_PLACEHOLDER
-                  ? { appSecret: currentChannel.appSecret }
-                  : {}),
-              },
-            ];
-          },
-        ),
-      )
-    : undefined;
-
-  return {
-    ...patch,
-    ...(patch.network?.proxy?.password === SENSITIVE_PLACEHOLDER
-      ? {
-          network: {
-            ...patch.network,
-            proxy: {
-              ...patch.network.proxy,
-              password: current.network.proxy.password,
-            },
-          },
-        }
-      : {}),
-    ...(botChannels
-      ? {
-          botChat: {
-            ...patch.botChat,
-            channels: botChannels,
-          },
-        }
-      : {}),
-  };
-}
-
+export function maskAppSettings(
+  settings: RuntimeHostAppSettings,
+  revealPatch?: UpdateAppSettingsInput,
+): RuntimeHostAppSettings;
+export function maskAppSettings(
+  settings: AppSettings,
+  revealPatch?: UpdateAppSettingsInput,
+): AppSettings;
 export function maskAppSettings(
   settings: AppSettings,
   revealPatch: UpdateAppSettingsInput = {},
 ): AppSettings {
   return {
     ...settings,
-    network: {
-      ...settings.network,
-      proxy: {
-        ...settings.network.proxy,
-        password: shouldReveal(revealPatch.network?.proxy?.password)
-          ? settings.network.proxy.password
-          : (maskSensitive(settings.network.proxy.password) ?? ""),
-      },
-    },
     botChat: {
       ...settings.botChat,
       channels: Object.fromEntries(
@@ -183,6 +137,7 @@ export function stripSettingsSecretsForExport(
 ): Record<string, unknown> {
   const proxy = { ...settings.network.proxy } as Record<string, unknown>;
   delete proxy.password;
+  delete proxy.passwordConfigured;
 
   const channels: Record<string, unknown> = {};
   for (const [provider, channel] of Object.entries(settings.botChat.channels)) {
@@ -209,6 +164,14 @@ export function stripSettingsSecretsForExport(
   };
 }
 
+export function buildSettingsUpdateResult(
+  settings: RuntimeHostAppSettings,
+  patch: UpdateAppSettingsInput,
+): UpdateAppSettingsResult<RuntimeHostAppSettings>;
+export function buildSettingsUpdateResult(
+  settings: AppSettings,
+  patch: UpdateAppSettingsInput,
+): UpdateAppSettingsResult;
 export function buildSettingsUpdateResult(
   settings: AppSettings,
   patch: UpdateAppSettingsInput,
diff --git a/apps/desktop/src/preload/bridge-contract.d.ts b/apps/desktop/src/preload/bridge-contract.d.ts
index 33949c85e0..1b0183f1c4 100644
--- a/apps/desktop/src/preload/bridge-contract.d.ts
+++ b/apps/desktop/src/preload/bridge-contract.d.ts
@@ -31,6 +31,7 @@ import type {
   AppIconChoice,
   AppIconTarget,
   AppSettings,
+  RuntimeHostAppSettings,
   ChatDefaultsSettings,
   SettingsTestResult,
   UpdateAppSettingsInput,
@@ -1425,9 +1426,9 @@ export interface MakaBridge {
   };
   settings: {
     getClient(): Promise<AppSettings>;
-    get(host?: DesktopRuntimeHostRef): Promise<AppSettings>;
+    get(host?: DesktopRuntimeHostRef): Promise<RuntimeHostAppSettings>;
     updateClient(patch: UpdateAppSettingsInput): Promise<UpdateAppSettingsResult>;
-    update(patch: UpdateAppSettingsInput, host?: DesktopRuntimeHostRef): Promise<UpdateAppSettingsResult>;
+    update(patch: UpdateAppSettingsInput, host?: DesktopRuntimeHostRef): Promise<UpdateAppSettingsResult<RuntimeHostAppSettings>>;
     subscribeClientChanged(handler: () => void): () => void;
     subscribeExternalChanged(handler: () => void, host?: DesktopRuntimeHostRef): () => void;
     testNetworkProxy(input?: TestProxyInput, host?: DesktopRuntimeHostRef): Promise<SettingsTestResult>;
diff --git a/apps/desktop/src/preload/preload.ts b/apps/desktop/src/preload/preload.ts
index 0876bccc7b..11a663f495 100644
--- a/apps/desktop/src/preload/preload.ts
+++ b/apps/desktop/src/preload/preload.ts
@@ -110,6 +110,7 @@ import type {
   AppIconChoice,
   AppIconTarget,
   AppSettings,
+  RuntimeHostAppSettings,
   SettingsTestResult,
   UpdateAppSettingsInput,
   UpdateAppSettingsResult,
@@ -3045,13 +3046,13 @@ const makaBridge = {
     getClient(): Promise<AppSettings> {
       return ipcRenderer.invoke('settings:client:get');
     },
-    get(host?: DesktopRuntimeHostRef): Promise<AppSettings> {
+    get(host?: DesktopRuntimeHostRef): Promise<RuntimeHostAppSettings> {
       return invokeSelectedRuntimeHost(host, 'settings:get');
     },
     updateClient(patch: UpdateAppSettingsInput): Promise<UpdateAppSettingsResult> {
       return ipcRenderer.invoke('settings:client:update', patch);
     },
-    update(patch: UpdateAppSettingsInput, host?: DesktopRuntimeHostRef): Promise<UpdateAppSettingsResult> {
+    update(patch: UpdateAppSettingsInput, host?: DesktopRuntimeHostRef): Promise<UpdateAppSettingsResult<RuntimeHostAppSettings>> {
       return invokeSelectedRuntimeHost(host, 'settings:update', patch);
     },
     subscribeClientChanged(handler: () => void): () => void {
diff --git a/apps/desktop/src/renderer/features/network-proxy/controller/use-proxy-password-draft.ts b/apps/desktop/src/renderer/features/network-proxy/controller/use-proxy-password-draft.ts
new file mode 100644
index 0000000000..6db03e5f8d
--- /dev/null
+++ b/apps/desktop/src/renderer/features/network-proxy/controller/use-proxy-password-draft.ts
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { useEffect, useReducer, useRef } from "react";
+import {
+  createProxyPasswordDraft,
+  type ProxyPasswordDraft,
+} from "../model/proxy-password-draft.js";
+
+export function useProxyPasswordDraft(
+  save: (secret: string) => Promise<void>,
+): ProxyPasswordDraft {
+  const saveRef = useRef(save);
+  saveRef.current = save;
+  const draftRef = useRef<ProxyPasswordDraft | null>(null);
+  draftRef.current ??= createProxyPasswordDraft((secret) =>
+    saveRef.current(secret),
+  );
+  const draft = draftRef.current;
+  const [, rerender] = useReducer((value: number) => value + 1, 0);
+  useEffect(() => draft.subscribe(rerender), [draft]);
+  return draft;
+}
diff --git a/apps/desktop/src/renderer/features/network-proxy/index.ts b/apps/desktop/src/renderer/features/network-proxy/index.ts
new file mode 100644
index 0000000000..ef56eb868b
--- /dev/null
+++ b/apps/desktop/src/renderer/features/network-proxy/index.ts
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import type { ReactNode } from "react";
+import { useProxyPasswordDraft } from "./controller/use-proxy-password-draft.js";
+import type { ProxyPasswordDraft } from "./model/proxy-password-draft.js";
+
+export {
+  runAfterProxyPasswordCommit,
+  type ProxyPasswordDraft,
+} from "./model/proxy-password-draft.js";
+export type { TestProxyInput } from "@maka/core/settings/network-settings";
+
+export function NetworkProxyPasswordDraft(props: {
+  save(secret: string): Promise<void>;
+  children(draft: ProxyPasswordDraft): ReactNode;
+}) {
+  return props.children(useProxyPasswordDraft(props.save));
+}
diff --git a/apps/desktop/src/renderer/features/network-proxy/model/proxy-password-draft.ts b/apps/desktop/src/renderer/features/network-proxy/model/proxy-password-draft.ts
new file mode 100644
index 0000000000..188919efc9
--- /dev/null
+++ b/apps/desktop/src/renderer/features/network-proxy/model/proxy-password-draft.ts
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export interface ProxyPasswordDraft {
+  readonly value: string;
+  readonly pending: boolean;
+  edit(value: string): void;
+  commit(): Promise<void>;
+  cancel(): void;
+  subscribe(listener: () => void): () => void;
+}
+
+export async function runAfterProxyPasswordCommit<T>(
+  draft: Pick<ProxyPasswordDraft, "commit">,
+  operation: () => Promise<T>,
+): Promise<T> {
+  await draft.commit();
+  return operation();
+}
+
+interface ActiveSave {
+  readonly secret: string;
+  readonly promise: Promise<void>;
+}
+
+/** Owns the write-only password draft and hides save de-duplication from UI callers. */
+export function createProxyPasswordDraft(
+  save: (secret: string) => Promise<void>,
+): ProxyPasswordDraft {
+  let value = "";
+  let active: ActiveSave | undefined;
+  const listeners = new Set<() => void>();
+
+  function notify(): void {
+    for (const listener of listeners) listener();
+  }
+
+  function commit(): Promise<void> {
+    if (active) {
+      if (!value || value === active.secret) return active.promise;
+      return active.promise.then(() => commit());
+    }
+    if (!value) return Promise.resolve();
+
+    const secret = value;
+    let write: Promise<void>;
+    try {
+      write = save(secret);
+    } catch (error) {
+      write = Promise.reject(error);
+    }
+    const promise = write
+      .then(() => {
+        if (value === secret) value = "";
+      })
+      .finally(() => {
+        if (active?.promise === promise) active = undefined;
+        notify();
+      });
+    active = { secret, promise };
+    notify();
+    return promise;
+  }
+
+  return {
+    get value() {
+      return value;
+    },
+    get pending() {
+      return active !== undefined;
+    },
+    edit(next) {
+      if (next === value) return;
+      value = next;
+      notify();
+    },
+    commit,
+    cancel() {
+      const next = active?.secret ?? "";
+      if (next === value) return;
+      value = next;
+      notify();
+    },
+    subscribe(listener) {
+      listeners.add(listener);
+      return () => listeners.delete(listener);
+    },
+  };
+}
diff --git a/apps/desktop/src/renderer/features/network-proxy/testing.ts b/apps/desktop/src/renderer/features/network-proxy/testing.ts
new file mode 100644
index 0000000000..35853bba89
--- /dev/null
+++ b/apps/desktop/src/renderer/features/network-proxy/testing.ts
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export {
+  createProxyPasswordDraft,
+  runAfterProxyPasswordCommit,
+} from "./model/proxy-password-draft.js";
diff --git a/apps/desktop/src/renderer/locales/settings-preferences-copy.ts b/apps/desktop/src/renderer/locales/settings-preferences-copy.ts
index 770e7e9953..3c742388d7 100644
--- a/apps/desktop/src/renderer/locales/settings-preferences-copy.ts
+++ b/apps/desktop/src/renderer/locales/settings-preferences-copy.ts
@@ -207,6 +207,7 @@ export type SettingsPreferencesCopy = {
     enableProxyAuth: string;
     username: string;
     password: string;
+    passwordSavedPlaceholder: string;
     bypassList: string;
     bypassHelp: string;
     autoBypass(count: number): string;
@@ -335,6 +336,7 @@ const SETTINGS_PREFERENCES_COPY_BY_LOCALE = {
       defaultModel: '默认模型', defaultModelHelp: '新任务默认使用的模型。', notSet: '未设置', saveDefaultModelFailed: '保存默认模型失败', defaultPermission: '默认权限模式', defaultPermissionHelp: '新任务默认使用的权限模式;可在任务内随时切换。', saveDefaultPermissionFailed: '保存默认权限模式失败', defaultThinking: '默认思考级别', defaultThinkingHelp: '新任务的思考级别;当前模型不支持所选级别时用模型默认。', followModelDefault: '跟随模型默认', saveDefaultThinkingFailed: '保存默认思考级别失败',
       shellPreference: 'Bash 工具 shell', shellPreferenceHelp: '自动模式保持 Windows 的 PowerShell 优先规则;Git Bash 是仅对当前 Runtime Host 生效的显式覆盖。', shellAuto: '自动(推荐)', shellGitBash: 'Git Bash', shellExecutable: 'Git Bash 可执行文件', shellExecutableHelp: '填写 Runtime Host 所在 Windows 机器上 bash.exe 的绝对路径。也支持该机器上的旧版 System32 WSL Bash;保存时会验证 GNU Bash。', saveShell: '保存 shell 设置', savingShell: '正在保存…', shellSaved: '已保存', saveShellFailed: '保存 shell 设置失败', shellExecutableRejected: '当前 Runtime Host 无法把该路径作为 GNU Bash [...]
       proxy: '代理服务器', proxyHelp: '为 AI 模型请求配置网络代理', enableProxy: '启用代理服务器', saveNetworkFailed: '保存网络设置失败', proxyProtocol: '代理协议', serverAddress: '服务器地址', port: '端口', proxyAuth: '代理认证', proxyAuthHelp: '需要用户名和密码时开启。', enableProxyAuth: '启用代理认证', username: '用户名', password: '密码', bypassList: '代理白名单', bypassHelp: '这些域名将绕过代理直连,多个用逗号分隔。', autoBypass: (count) => `已自动添加 ${count} 个域名。代理仅作用于 AI 模型请求。`, testing: '测试中…', testCurrent: '测试当前配置', proxyReachable: '代理可达', proxyTestFailed: '代理测试失败', proxyTe [...]
+      passwordSavedPlaceholder: '密码已保存;输入新密码以替换',
     },
     about: {
       loadFailed: '载入关于信息失败', loading: '正在加载关于页', unavailable: '无法载入关于信息', copied: '已复制诊断信息', pasteHint: '检查内容后,可直接粘贴到问题报告', copyFailed: '复制失败', clipboardUnavailable: '剪贴板不可用或被系统拒绝。', devBuild: '本地开发版', packagedBuild: '正式版', subtitle: '本地优先的 AI 助手 · 桌面端运行环境', privacyLabel: '隐私与安全', privacyTitle: '本地优先 · 隐私默认', privacyPoints: ['所有任务、设置、凭据和 Skill 指令文件都保留在本机工作区。', '模型密钥保存在本机凭据文件内;订阅账号令牌使用系统安全存储。', 'Maka 不发送使用遥测;只在你显式启用时与所选模型供应商通信。', '高风险工具操作需要在任务内明示授权。', '每个任务都会在本机保留消息、工具调用、权限决策与模式变更记录。'],  [...]
@@ -388,6 +390,7 @@ const SETTINGS_PREFERENCES_COPY_BY_LOCALE = {
     general: {
       incognito: 'Incognito mode', incognitoHelp: 'Pause local memory, web search, and scheduled task triggers.', enableIncognito: 'Enable incognito mode', incognitoFailed: 'Could not change incognito mode', notifications: 'Send a system notification when finished', notificationsHelp: 'Notify when a response finishes or fails while the window is in the background.', notificationsFailed: 'Could not change notification settings', workspaceInstructions: 'Follow project instructions', worksp [...]
       shellPreference: 'Bash tool shell', shellPreferenceHelp: 'Automatic keeps the PowerShell-first Windows default. Git Bash is an explicit override for the current Runtime Host.', shellAuto: 'Automatic (recommended)', shellGitBash: 'Git Bash', shellExecutable: 'Git Bash executable', shellExecutableHelp: 'Enter the absolute path to bash.exe on the Windows machine running the Runtime Host. The legacy System32 WSL Bash shim is also recognized; Maka verifies GNU Bash before saving.', save [...]
+      passwordSavedPlaceholder: 'Password saved; enter a new password to replace it',
     },
     about: {
       loadFailed: 'Could not load About information', loading: 'Loading About', unavailable: 'About information is unavailable', copied: 'Diagnostics copied', pasteHint: 'Review the content, then paste it into an issue report', copyFailed: 'Copy failed', clipboardUnavailable: 'The clipboard is unavailable or access was denied.', devBuild: 'Local development build', packagedBuild: 'Release build', subtitle: 'A local-first AI assistant · Desktop runtime', privacyLabel: 'Privacy and securit [...]
diff --git a/apps/desktop/src/renderer/locales/settings-test-result-copy.ts b/apps/desktop/src/renderer/locales/settings-test-result-copy.ts
index 66d8a316f0..48a4097fb9 100644
--- a/apps/desktop/src/renderer/locales/settings-test-result-copy.ts
+++ b/apps/desktop/src/renderer/locales/settings-test-result-copy.ts
@@ -29,6 +29,7 @@ type SettingsTestResultCopy = {
     ) => string;
     disabled: string;
     configurationMissing: string;
+    credentialMissing: string;
     timeout: string;
     httpError: (status: number | undefined) => string;
     unreachable: string;
@@ -49,6 +50,7 @@ const COPY = {
         ["代理配置有效", endpoint, location].filter(Boolean).join(" · "),
       disabled: "请先启用代理服务器,再进行测试。",
       configurationMissing: "请填写代理服务器地址和端口后再测试。",
+      credentialMissing: "代理认证已开启,请输入代理密码后再测试。",
       timeout: "代理测试超时,请检查代理服务是否可达。",
       httpError: (status) =>
         status === undefined
@@ -75,6 +77,8 @@ const COPY = {
           .join(" · "),
       disabled: "Enable the proxy server before testing it.",
       configurationMissing: "Enter a proxy host and port before testing it.",
+      credentialMissing:
+        "Proxy authentication is enabled. Enter a proxy password before testing.",
       timeout:
         "The proxy test timed out. Check whether the proxy service is reachable.",
       httpError: (status) =>
@@ -115,6 +119,8 @@ export function settingsTestResultMessage(
       return copy.proxy.disabled;
     case "proxy_configuration_missing":
       return copy.proxy.configurationMissing;
+    case "proxy_credential_missing":
+      return copy.proxy.credentialMissing;
     case "proxy_timeout":
       return copy.proxy.timeout;
     case "proxy_http_error":
diff --git a/apps/desktop/src/renderer/settings/general-settings-page.tsx b/apps/desktop/src/renderer/settings/general-settings-page.tsx
index 42b0a0dd17..1bf53b36d9 100644
--- a/apps/desktop/src/renderer/settings/general-settings-page.tsx
+++ b/apps/desktop/src/renderer/settings/general-settings-page.tsx
@@ -31,6 +31,7 @@ import type {
   ChatDefaultPermissionMode,
   ShellPreference,
   NetworkProxySettings,
+  RuntimeHostNetworkProxySettings,
   UpdateAppSettingsResult,
 } from '@maka/core/settings';
 import { THINKING_LEVELS, type ThinkingLevel } from '@maka/core/model-thinking';
@@ -38,7 +39,6 @@ import type {
   IdentifiedLlmConnection,
   ProjectedLlmConnection,
 } from '@maka/core/llm-connections';
-import type { TestProxyInput } from "@maka/core/settings/network-settings";
 import { buildChatModelChoices } from "@maka/core/chat-model-choice";
 import {
   Button,
@@ -63,6 +63,12 @@ import { getConversationCopy } from '@maka/ui';
 import { settingsActionErrorMessage } from "./settings-error-copy";
 import { useActionGuard, useKeyedActionGuard } from "./use-action-guard";
 import { useOptimisticSettingsDraft } from "./use-optimistic-settings-draft";
+import {
+  NetworkProxyPasswordDraft,
+  runAfterProxyPasswordCommit,
+  type ProxyPasswordDraft,
+  type TestProxyInput,
+} from "../features/network-proxy/index.js";
 import { getSettingsPreferencesCopy } from "../locales/settings-preferences-copy.js";
 import { settingsTestResultMessage } from "../locales/settings-test-result-copy.js";
 import { getShellCopy } from "../locales/shell-copy.js";
@@ -748,29 +754,35 @@ function NetworkProxySection(props: {
   const host = useRuntimeHostSettingsTarget();
   const locale = useUiLocale();
   const copy = getSettingsPreferencesCopy(locale).general;
-  const persistedProxy = props.settings.network.proxy;
+  const persistedProxy = props.settings.network
+    .proxy as RuntimeHostNetworkProxySettings;
   const [testing, setTesting] = useState(false);
   const proxyTestGuard = useActionGuard<"test">();
   const toast = useToast();
+  function reportNetworkSaveError(error: unknown): void {
+    toast.error(
+      copy.saveNetworkFailed,
+      settingsActionErrorMessage(error, locale),
+      undefined,
+      { profileId: host.profileId },
+    );
+  }
   const {
     draft: proxyDraft,
     draftRef: proxyDraftRef,
     mountedRef: networkPageMountedRef,
     update,
-  } = useOptimisticSettingsDraft<NetworkProxySettings>(
+  } = useOptimisticSettingsDraft<RuntimeHostNetworkProxySettings>(
     persistedProxy,
     (patch) =>
       props
         .onUpdate({ network: { proxy: patch } })
-        .then((result) => result.settings.network.proxy),
+        .then(
+          (result) =>
+            result.settings.network.proxy as RuntimeHostNetworkProxySettings,
+    ),
     {
-      onError: (error) =>
-        toast.error(
-          copy.saveNetworkFailed,
-          settingsActionErrorMessage(error, locale),
-          undefined,
-          { profileId: host.profileId },
-        ),
+      onError: reportNetworkSaveError,
     },
   );
 
@@ -779,12 +791,27 @@ function NetworkProxySection(props: {
     return update(patch);
   }
 
-  async function testProxy() {
+  async function saveProxyPassword(secret: string) {
+    try {
+      await props.onUpdate({
+        network: {
+          proxy: { credential: { kind: "replace", secret } },
+        },
+      });
+    } catch (error) {
+      reportNetworkSaveError(error);
+      throw error;
+    }
+  }
+
+  async function testProxy(passwordDraft: ProxyPasswordDraft) {
     if (!props.isInteractive) return;
     if (!proxyTestGuard.begin("test")) return;
     setTesting(true);
     try {
-      const result = await props.testNetworkProxy(toProxyTestInput(proxyDraftRef.current));
+      const result = await runAfterProxyPasswordCommit(passwordDraft, () =>
+        props.testNetworkProxy(toProxyTestInput(proxyDraftRef.current)),
+      );
       const latency =
         result.latencyMs !== undefined ? ` · ${result.latencyMs} ms` : "";
       const message = settingsTestResultMessage(result, locale);
@@ -816,7 +843,9 @@ function NetworkProxySection(props: {
   }
 
   return (
-    <>
+    <NetworkProxyPasswordDraft save={saveProxyPassword}>
+      {(passwordDraft) => (
+        <>
       <SettingsRow
         label={copy.proxy}
         description={copy.proxyHelp}
@@ -877,7 +906,16 @@ function NetworkProxySection(props: {
                 isLabelHidden
                 value={proxyDraft.authEnabled}
                 isDisabled={!props.isInteractive}
-                onChange={(authEnabled) => void updateProxy({ authEnabled })}
+                onChange={(authEnabled) => {
+                  if (authEnabled) {
+                    void updateProxy({ authEnabled });
+                    return;
+                  }
+                  passwordDraft.cancel();
+                  void updateProxy({ authEnabled }).then((saved) => {
+                    if (saved) passwordDraft.cancel();
+                  });
+                }}
               />
             }
           />
@@ -892,8 +930,22 @@ function NetworkProxySection(props: {
                   isDisabled={!props.isInteractive}
                 />
                 <PasswordInput
-                  value={proxyDraft.password}
-                  onChange={(next) => void updateProxy({ password: next })}
+                  value={passwordDraft.value}
+                  onChange={passwordDraft.edit}
+                  onFocusExit={() => void passwordDraft.commit().catch(() => {})}
+                  onEnter={() => void passwordDraft.commit().catch(() => {})}
+                  onKeyDown={(event) => {
+                    if (event.key !== "Escape") return;
+                    event.preventDefault();
+                    event.stopPropagation();
+                    passwordDraft.cancel();
+                  }}
+                  hasCopyAction={false}
+                  placeholder={
+                    proxyDraft.passwordConfigured
+                      ? copy.passwordSavedPlaceholder
+                      : undefined
+                  }
                   label={copy.password}
                   isDisabled={!props.isInteractive}
                 />
@@ -927,13 +979,15 @@ function NetworkProxySection(props: {
               variant="primary"
               isLoading={testing}
               isDisabled={!props.isInteractive}
-              onClick={() => void testProxy()}
+              onClick={() => void testProxy(passwordDraft)}
               label={copy.testCurrent}
             />
           </SettingsActions>
         </>
       )}
-    </>
+        </>
+      )}
+    </NetworkProxyPasswordDraft>
   );
 }
 
@@ -949,8 +1003,6 @@ function toProxyTestInput(proxy: NetworkProxySettings): TestProxyInput {
         proxy.authEnabled && proxy.username.trim()
           ? proxy.username.trim()
           : undefined,
-      password:
-        proxy.authEnabled && proxy.password ? proxy.password : undefined,
       bypassList: proxy.bypassList,
     },
   };
diff --git a/apps/desktop/src/renderer/settings/password-input.tsx b/apps/desktop/src/renderer/settings/password-input.tsx
index 7aa0ac37fa..6629e9d3fa 100644
--- a/apps/desktop/src/renderer/settings/password-input.tsx
+++ b/apps/desktop/src/renderer/settings/password-input.tsx
@@ -17,7 +17,13 @@
  * under the License.
  */
 
-import { useEffect, useRef, useState, type ReactNode } from 'react';
+import {
+  useEffect,
+  useRef,
+  useState,
+  type KeyboardEvent,
+  type ReactNode,
+} from 'react';
 import { ICON_SIZE, Check, Copy, Eye, EyeOff } from '@maka/ui/icons';
 import {
   IconButton,
@@ -63,7 +69,10 @@ export function PasswordInput(props: {
   isRequired?: boolean;
   isOptional?: boolean;
   isDisabled?: boolean;
-  onBlur?(): void;
+  onFocusExit?(): void;
+  onEnter?(): void;
+  onKeyDown?(event: KeyboardEvent<HTMLInputElement>): void;
+  hasCopyAction?: boolean;
   hasAutoFocus?: boolean;
 }) {
   const copy = getSettingsPreferencesCopy(useUiLocale()).password;
@@ -125,12 +134,29 @@ export function PasswordInput(props: {
       isRequired={props.isRequired}
       isOptional={props.isOptional}
       status={props.status}
+      onBlurCapture={(event) => {
+        const destination = event.relatedTarget;
+        if (!destination && !event.currentTarget.ownerDocument.hasFocus()) {
+          return;
+        }
+        if (
+          destination &&
+          event.currentTarget.contains(destination as Node)
+        ) {
+          return;
+        }
+        props.onFocusExit?.();
+      }}
     >
       <TextInput
         type={visible ? 'text' : 'password'}
         value={props.value}
         onChange={(value) => props.onChange(value)}
-        onBlur={props.onBlur}
+        onKeyDown={(event) => {
+          if (event.nativeEvent.isComposing || event.key === 'Process') return;
+          if (event.key === 'Enter') props.onEnter?.();
+          props.onKeyDown?.(event);
+        }}
         placeholder={props.placeholder}
         label={copy.value}
         isLabelHidden
@@ -141,7 +167,7 @@ export function PasswordInput(props: {
       />
       {/* InputGroupText: the sanctioned addon segment — bare IconButtons break the group's caps. */}
       <InputGroupText>
-        {props.value && !props.isDisabled && (
+        {(props.hasCopyAction ?? true) && props.value && !props.isDisabled && (
           <IconButton
             variant="ghost"
             size="sm"
diff --git a/apps/desktop/src/renderer/settings/settings-snapshot-cache.ts b/apps/desktop/src/renderer/settings/settings-snapshot-cache.ts
index 278cc98f99..b06a09041e 100644
--- a/apps/desktop/src/renderer/settings/settings-snapshot-cache.ts
+++ b/apps/desktop/src/renderer/settings/settings-snapshot-cache.ts
@@ -17,9 +17,8 @@
  * under the License.
  */
 
-import type { AppSettings } from '@maka/core/settings';
+import type { AppSettings, RuntimeHostAppSettings } from '@maka/core/settings';
 import type {
-  IdentifiedLlmConnection,
   ProjectedLlmConnection,
 } from '@maka/core/llm-connections';
 import type {
@@ -39,8 +38,8 @@ export interface SettingsSnapshotCache {
   readRuntimeHostCatalog(): DesktopRuntimeHostProfileSnapshot | undefined;
   commitRuntimeHostCatalogRead(snapshot: DesktopRuntimeHostProfileSnapshot): void;
 
-  readRuntimeHostSettings(key: string): AppSettings | undefined;
-  commitRuntimeHostSettingsRead(key: string, snapshot: AppSettings): void;
+  readRuntimeHostSettings(key: string): RuntimeHostAppSettings | undefined;
+  commitRuntimeHostSettingsRead(key: string, snapshot: RuntimeHostAppSettings): void;
 
   readRuntimeHostConnections(key: string): RuntimeHostConnectionsSnapshot | undefined;
   commitRuntimeHostConnectionsRead(
@@ -61,7 +60,7 @@ export function runtimeHostSettingsKey(host: DesktopRuntimeHostRef): string {
 export function createSettingsSnapshotCache(): SettingsSnapshotCache {
   let client: AppSettings | undefined;
   let runtimeHostCatalog: DesktopRuntimeHostProfileSnapshot | undefined;
-  const runtimeHostSettings = new Map<string, AppSettings>();
+  const runtimeHostSettings = new Map<string, RuntimeHostAppSettings>();
   const runtimeHostConnections = new Map<string, RuntimeHostConnectionsSnapshot>();
 
   return {
diff --git a/apps/desktop/src/renderer/settings/settings-surface.tsx b/apps/desktop/src/renderer/settings/settings-surface.tsx
index 73517879bf..d6bae697cd 100644
--- a/apps/desktop/src/renderer/settings/settings-surface.tsx
+++ b/apps/desktop/src/renderer/settings/settings-surface.tsx
@@ -41,6 +41,7 @@ import {
 import { ICON_SIZE, ArrowLeft } from '@maka/ui/icons';
 import type {
   AppSettings,
+  RuntimeHostAppSettings,
   ChatDefaultPermissionMode,
   SettingsSection,
   ThemePalette,
@@ -292,7 +293,7 @@ function SettingsSurfaceContent(
     initialClientSettings ?? defaultSettings,
   );
   const [runtimeHostSettings, setRuntimeHostSettings] = useState<
-    SettingsResourceState<AppSettings>
+    SettingsResourceState<RuntimeHostAppSettings>
   >(() => createSettingsResourceState(
     initialRuntimeHostKey,
     initialRuntimeHostKey
@@ -635,7 +636,10 @@ function SettingsSurfaceContent(
         return result;
       }
       if (acceptedHostUpdate && hostKey) {
-        setRuntimeHostSettings(completeSettingsResourceLoad(hostKey, result.settings));
+        setRuntimeHostSettings(completeSettingsResourceLoad(
+          hostKey,
+          result.settings as RuntimeHostAppSettings,
+        ));
         void reloadRuntimeHostSettings(host);
       } else if (
         clientTicket !== undefined &&
diff --git a/apps/desktop/stories/settings/settings-pages.stories.tsx b/apps/desktop/stories/settings/settings-pages.stories.tsx
index 5195fe534f..112167a433 100644
--- a/apps/desktop/stories/settings/settings-pages.stories.tsx
+++ b/apps/desktop/stories/settings/settings-pages.stories.tsx
@@ -23,6 +23,7 @@ import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
 import { ToastProvider, useToast } from '@maka/ui';
 import type {
   AppSettings,
+  RuntimeHostAppSettings,
   SettingsSection,
   ThemePalette,
   ThemePreference,
@@ -709,11 +710,29 @@ const unavailableRuntimeHostProfiles: DesktopRuntimeHostProfileSnapshot = {
 
 const STORY_RUNTIME_HOST_KEY = 'local:storybook-local-host';
 
+function storyRuntimeSettings(
+  settings: AppSettings = createDefaultSettings(),
+  passwordConfigured = false,
+): RuntimeHostAppSettings {
+  return {
+    ...settings,
+    network: {
+      proxy: {
+        ...settings.network.proxy,
+        passwordConfigured,
+      },
+    },
+  };
+}
+
 function seedGeneralSnapshotCache(cache: SettingsSnapshotCache): void {
   const settings = createDefaultSettings();
   cache.commitClientRead(settings);
   cache.commitRuntimeHostCatalogRead(runtimeHostProfiles);
-  cache.commitRuntimeHostSettingsRead(STORY_RUNTIME_HOST_KEY, settings);
+  cache.commitRuntimeHostSettingsRead(
+    STORY_RUNTIME_HOST_KEY,
+    storyRuntimeSettings(settings),
+  );
   cache.commitRuntimeHostConnectionsRead(STORY_RUNTIME_HOST_KEY, {
     connections,
     defaultSlug: 'zai-live',
@@ -734,7 +753,7 @@ function seedGeneralTwoHostSnapshotCache(cache: SettingsSnapshotCache): void {
 }
 
 let storyClientSettings = createDefaultSettings();
-let storyRuntimeHostSettings = createDefaultSettings();
+let storyRuntimeHostSettings = storyRuntimeSettings();
 
 const makaBridge = {
   runtimeHostProfiles: {
@@ -780,7 +799,16 @@ const makaBridge = {
       return { settings: storyClientSettings };
     },
     update: async (patch: Parameters<typeof window.maka.settings.update>[0]): Promise<UpdateAppSettingsResult> => {
-      storyRuntimeHostSettings = mergeSettings(storyRuntimeHostSettings, patch);
+      const merged = mergeSettings(storyRuntimeHostSettings, patch);
+      storyRuntimeHostSettings = storyRuntimeSettings(
+        merged,
+        patch.network?.proxy?.credential?.kind === 'replace'
+          ? true
+          : patch.network?.proxy?.credential?.kind === 'delete' ||
+              patch.network?.proxy?.authEnabled === false
+            ? false
+            : storyRuntimeHostSettings.network.proxy.passwordConfigured,
+      );
       return { settings: storyRuntimeHostSettings };
     },
     subscribeClientChanged: () => () => undefined,
diff --git a/docs/windows-test-inventory.md b/docs/windows-test-inventory.md
index 5e96b5f86d..d13667bfd7 100644
--- a/docs/windows-test-inventory.md
+++ b/docs/windows-test-inventory.md
@@ -16,10 +16,10 @@ Locations intentionally omit line numbers so unrelated edits do not invalidate t
 | Classification | Count |
 |---|---:|
 | windows-backend-gap | 27 |
-| portable-candidate | 14 |
+| portable-candidate | 18 |
 | platform-contract | 31 |
 
-Total Windows-excluded declarations: **72**
+Total Windows-excluded declarations: **76**
 
 ## Inventory
 
@@ -91,6 +91,10 @@ Total Windows-excluded declarations: **72**
 | platform-contract | `packages/storage/src/__tests__/runtime-policy-stores.test.ts` validates proxy policy mutations before clearing and reports failed follow-up commits as unknown | `process.platform === 'win32' ? 'POSIX permissions are required to inject a persistence failure' : false` |
 | platform-contract | `packages/storage/src/__tests__/runtime-policy-stores.test.ts` reports unknown outcome when active proxy password persistence fails after clearing | `process.platform === 'win32' ? 'POSIX permissions are required to inject a persistence failure' : false` |
 | platform-contract | `packages/storage/src/__tests__/runtime-policy-stores.test.ts` preserves unknown commit semantics and consumes the completion ticket | `process.platform === 'win32' ? 'POSIX permissions are required to inject a persistence failure' : false` |
+| portable-candidate | `packages/storage/src/__tests__/runtime-policy-stores.test.ts` proxy replacement failure before vault publication leaves both stores unchanged | `process.platform === 'win32' ? 'POSIX file handles are required to inject persistence failures' : false` |
+| portable-candidate | `packages/storage/src/__tests__/runtime-policy-stores.test.ts` proxy replacement never persists its secret outside the credential vault | `process.platform === 'win32' ? 'POSIX file handles are required to inject persistence failures' : false` |
+| portable-candidate | `packages/storage/src/__tests__/runtime-policy-stores.test.ts` authentication disable failure before policy publication leaves both stores unchanged | `process.platform === 'win32' ? 'POSIX file handles are required to inject persistence failures' : false` |
+| portable-candidate | `packages/storage/src/__tests__/runtime-policy-stores.test.ts` disabling proxy authentication commits policy before deleting its credential | `process.platform === 'win32' ? 'POSIX file handles are required to inject persistence failures' : false` |
 | platform-contract | `packages/storage/src/__tests__/runtime-policy-stores.test.ts` successor recovery removes credentials orphaned by an interrupted connection removal | `process.platform === 'win32' ? 'POSIX permissions are required to inject a persistence failure' : false` |
 | platform-contract | `packages/storage/src/__tests__/runtime-policy-stores.test.ts` fails closed on final symlinks, FIFOs, and oversized documents without changing bytes | `process.platform === 'win32'` |
 | portable-candidate | `packages/storage/src/__tests__/stable-storage.test.ts` rejects a symlink instead of following it | `process.platform === 'win32' ? 'POSIX no-follow semantics are required' : false` |
diff --git a/packages/core/src/__tests__/settings.test.ts b/packages/core/src/__tests__/settings.test.ts
index 2c9e54e2ec..acc1106af7 100644
--- a/packages/core/src/__tests__/settings.test.ts
+++ b/packages/core/src/__tests__/settings.test.ts
@@ -344,3 +344,38 @@ describe('app icon on upgrade', () => {
     assert.strictEqual(migrated.appearance.appIconDark, undefined);
   });
 });
+
+test('proxy credentials never enter persisted settings', () => {
+  const defaults = createDefaultSettings();
+  assert.strictEqual('password' in defaults.network.proxy, false);
+  assert.strictEqual('passwordConfigured' in defaults.network.proxy, false);
+
+  const merged = mergeSettings(defaults, {
+    network: {
+      proxy: {
+        host: '10.0.0.2',
+        credential: { kind: 'replace', secret: 'complete-secret' },
+        password: 'legacy-secret',
+        passwordConfigured: true,
+      },
+    },
+  } as never);
+
+  assert.strictEqual(merged.network.proxy.host, '10.0.0.2');
+  assert.strictEqual('credential' in merged.network.proxy, false);
+  assert.strictEqual('password' in merged.network.proxy, false);
+  assert.strictEqual('passwordConfigured' in merged.network.proxy, false);
+
+  const normalized = normalizeSettings({
+    network: {
+      proxy: {
+        password: 'legacy-secret',
+        passwordConfigured: true,
+        credential: { kind: 'delete' },
+      },
+    },
+  });
+  assert.strictEqual('credential' in normalized.network.proxy, false);
+  assert.strictEqual('password' in normalized.network.proxy, false);
+  assert.strictEqual('passwordConfigured' in normalized.network.proxy, false);
+});
diff --git a/packages/core/src/runtime-policy.ts b/packages/core/src/runtime-policy.ts
index 4d65b75c0f..336b79652e 100644
--- a/packages/core/src/runtime-policy.ts
+++ b/packages/core/src/runtime-policy.ts
@@ -26,7 +26,13 @@ import type {
 import type { ThinkingLevel } from './model-thinking.js';
 import type { ProviderType } from './provider-registry.js';
 import type { RelayModelProfile } from './model-thinking.js';
-import type { ChatDefaultPermissionMode, ProxyProtocol, ShellSettings } from './settings.js';
+import {
+  networkProxyCredentialTarget,
+  type ChatDefaultPermissionMode,
+  type NetworkProxyCredentialTarget,
+  type ProxyProtocol,
+  type ShellSettings,
+} from './settings.js';
 import type { SubagentSettings } from './subagent-settings.js';
 import type { JsonObject } from './request-customization.js';
 import {
@@ -36,6 +42,8 @@ import {
 } from './web-search.js';
 
 export { WEB_SEARCH_PROVIDERS };
+export { networkProxyCredentialTarget };
+export type { NetworkProxyCredentialTarget };
 export type { ConnectionTestErrorClass, ModelDiscoverySource } from './llm-connections.js';
 export {
   decodeRuntimePolicyEntityId,
@@ -43,7 +51,9 @@ export {
 } from './runtime-policy/domain-codec.js';
 export {
   decodeCanonicalRuntimePolicy,
+  normalizeNetworkProxyCredentialTarget,
   decodeRuntimePolicyV2,
+  normalizeNetworkProxyUpdate,
   normalizeRuntimePolicyMutation,
 } from './runtime-policy/policy-codec.js';
 export {
@@ -56,6 +66,7 @@ export {
   decodeCanonicalConnectionBaseUrl,
   decodeCanonicalConnectionCatalogEntry,
   decodeConnectionModelId,
+  decodeConnectionCredentialTarget,
   decodeRelayModelProfilesTable,
   decodeConnectionModel,
   decodeConnectionName,
@@ -69,6 +80,8 @@ export {
   normalizeConnectionCatalogEntryUpdate,
   normalizeConnectionCatalogEntryUpdateForProvider,
   normalizeConnectionModelDiscoveryResult,
+  canonicalConnectionEffectiveBaseUrl,
+  connectionCredentialTarget,
   normalizeCreateCatalogConnectionInput,
   normalizeRemoveCatalogConnectionInput,
   normalizeSetDefaultConnectionTargetInput,
@@ -186,6 +199,44 @@ export type MutateRuntimePolicyResult =
   | { readonly kind: 'committed'; readonly snapshot: RuntimePolicySnapshot }
   | RevisionConflict;
 
+export type NetworkProxyCredentialUpdate =
+  | { readonly kind: 'keep' }
+  | {
+      readonly kind: 'replace';
+      readonly secret: string;
+      readonly expectedTarget?: NetworkProxyCredentialTarget;
+    }
+  | { readonly kind: 'delete' };
+
+/**
+ * One optimistic basis for the Host-owned proxy policy and credential pair.
+ * The Runtime Host validates both generations before publishing either side.
+ */
+export interface UpdateNetworkProxyInput {
+  readonly expectedPolicyRevision: Revision;
+  readonly expectedCredential: CredentialVersionBasis | null;
+  readonly networkProxy: RuntimePolicy['networkProxy'];
+  readonly credential: NetworkProxyCredentialUpdate;
+}
+
+export type UpdateNetworkProxyResult =
+  | {
+      readonly kind: 'committed';
+      readonly snapshot: RuntimePolicySnapshot;
+      readonly credentialStatus: CredentialStatus;
+    }
+  | RevisionConflict
+  | {
+      readonly kind: 'proxy_target_mismatch';
+      readonly expected: NetworkProxyCredentialTarget;
+      readonly actual: NetworkProxyCredentialTarget;
+    }
+  | {
+      readonly kind: 'credential_stale';
+      readonly expected: CredentialVersionBasis | null;
+      readonly actual: CredentialVersionBasis | null;
+    };
+
 export function createDefaultRuntimePolicy(): RuntimePolicy {
   return {
     networkProxy: {
@@ -284,6 +335,12 @@ export interface ConnectionVersionBasis {
   readonly revision: Revision;
 }
 
+export interface ConnectionCredentialTarget extends ConnectionVersionBasis {
+  readonly slug: string;
+  readonly providerType: ProviderType;
+  readonly effectiveBaseUrl: string;
+}
+
 export interface ConnectionTarget {
   readonly connectionId: EntityId;
   readonly modelId: string;
@@ -390,6 +447,7 @@ export interface CredentialVaultSnapshot {
 export interface SetCredentialInput {
   readonly locator: CredentialLocator;
   readonly expected: (CredentialIdentity & { readonly revision: Revision }) | null;
+  readonly expectedConnection?: ConnectionCredentialTarget;
   readonly secret: string;
 }
 
@@ -400,6 +458,11 @@ export interface DeleteCredentialInput {
 export type CredentialMutationResult =
   | { readonly kind: 'committed'; readonly snapshot: CredentialVaultSnapshot }
   | { readonly kind: 'connection_not_found' }
+  | {
+      readonly kind: 'connection_stale';
+      readonly expected: ConnectionVersionBasis;
+      readonly actual: ConnectionVersionBasis | null;
+    }
   | {
       readonly kind: 'credential_stale';
       readonly expected: CredentialVersionBasis | null;
diff --git a/packages/core/src/runtime-policy/connection-catalog-codec.ts b/packages/core/src/runtime-policy/connection-catalog-codec.ts
index 39524ae772..67c5796987 100644
--- a/packages/core/src/runtime-policy/connection-catalog-codec.ts
+++ b/packages/core/src/runtime-policy/connection-catalog-codec.ts
@@ -20,6 +20,7 @@
 import {
   isModelModality,
   isRelayProviderType,
+  effectiveBaseUrl,
   PROVIDER_REGISTRY,
   providerDefaultsOf,
   validateSlug,
@@ -39,6 +40,7 @@ import {
 } from '../model-thinking.js';
 import type {
   ConnectionCatalogEntry,
+  ConnectionCredentialTarget,
   ConnectionCatalogEntryDraft,
   ConnectionCatalogEntryUpdate,
   ConnectionModel,
@@ -486,6 +488,67 @@ export function decodeConnectionVersionBasis(value: unknown): ConnectionVersionB
   };
 }
 
+export function canonicalConnectionEffectiveBaseUrl(
+  connection: Pick<ConnectionCatalogEntry, 'providerType' | 'baseUrl'>,
+): string {
+  const endpoint = effectiveBaseUrl(connection);
+  try {
+    return new URL(endpoint).toString();
+  } catch {
+    throw domainError('connection has an invalid effective base URL');
+  }
+}
+
+export function connectionCredentialTarget(
+  connection: Pick<
+    ConnectionCatalogEntry,
+    'connectionId' | 'revision' | 'slug' | 'providerType' | 'baseUrl'
+  >,
+): ConnectionCredentialTarget {
+  return {
+    connectionId: connection.connectionId,
+    revision: connection.revision,
+    slug: connection.slug,
+    providerType: connection.providerType,
+    effectiveBaseUrl: canonicalConnectionEffectiveBaseUrl(connection),
+  };
+}
+
+export function decodeConnectionCredentialTarget(value: unknown): ConnectionCredentialTarget {
+  const item = exactRecord(value, 'connection credential target', [
+    'connectionId',
+    'revision',
+    'slug',
+    'providerType',
+    'effectiveBaseUrl',
+  ]);
+  const version = decodeConnectionVersionBasis({
+    connectionId: item.connectionId,
+    revision: item.revision,
+  });
+  const providerType = decodeProviderType(item.providerType);
+  const effectiveBaseUrl = stringValue(
+    item.effectiveBaseUrl,
+    'connection credential target effective base URL',
+    2_048,
+  );
+  let canonical: string;
+  try {
+    canonical = new URL(effectiveBaseUrl).toString();
+  } catch {
+    throw domainError('connection credential target effective base URL must be valid');
+  }
+  if (canonical !== effectiveBaseUrl) {
+    throw domainError('connection credential target effective base URL must be canonical');
+  }
+  return {
+    ...version,
+    slug: decodeConnectionSlug(item.slug),
+    providerType,
+    effectiveBaseUrl,
+  };
+}
+
 export function decodeConnectionTarget(value: unknown): ConnectionTarget {
   const item = exactRecord(value, 'connection target', ['connectionId', 'modelId']);
   return {
diff --git a/packages/core/src/runtime-policy/credential-vault-codec.ts b/packages/core/src/runtime-policy/credential-vault-codec.ts
index e709baf3b5..28cd1a232d 100644
--- a/packages/core/src/runtime-policy/credential-vault-codec.ts
+++ b/packages/core/src/runtime-policy/credential-vault-codec.ts
@@ -24,6 +24,7 @@ import type {
   DeleteCredentialInput,
   SetCredentialInput,
 } from '../runtime-policy.js';
+import { decodeConnectionCredentialTarget } from './connection-catalog-codec.js';
 import { WEB_SEARCH_CREDENTIAL_PROVIDERS } from '../web-search.js';
 import {
   parseRequestHeaders,
@@ -124,7 +125,12 @@ export function decodeCredentialStatus(value: unknown): CredentialStatus {
 }
 
 export function normalizeSetCredentialInput(value: unknown): SetCredentialInput {
-  const input = exactRecord(value, 'set credential input', ['locator', 'expected', 'secret']);
+  const input = exactRecord(
+    value,
+    'set credential input',
+    ['locator', 'expected', 'expectedConnection', 'secret'],
+    ['locator', 'expected', 'secret'],
+  );
   let expected: SetCredentialInput['expected'];
   if (input.expected === null) {
     expected = null;
@@ -139,10 +145,18 @@ export function normalizeSetCredentialInput(value: unknown): SetCredentialInput
     };
   }
   const locator = decodeCredentialLocator(input.locator);
+  const expectedConnection =
+    input.expectedConnection === undefined
+      ? undefined
+      : decodeConnectionCredentialTarget(input.expectedConnection);
+  if (expectedConnection && locator.scope !== 'connection') {
+    throw domainError('only connection credentials accept a connection target basis');
+  }
   const secret = normalizeCredentialSecret(input.secret);
   return {
     locator,
     expected,
+    ...(expectedConnection === undefined ? {} : { expectedConnection }),
     secret:
       locator.scope === 'connection' && locator.kind === 'request_headers'
         ? normalizeRequestHeadersSecret(secret)
diff --git a/packages/core/src/runtime-policy/policy-codec.ts b/packages/core/src/runtime-policy/policy-codec.ts
index 442f19eb57..3462dbc01b 100644
--- a/packages/core/src/runtime-policy/policy-codec.ts
+++ b/packages/core/src/runtime-policy/policy-codec.ts
@@ -23,9 +23,16 @@ import { normalizeSubagentSettings } from '../subagent-settings.js';
 import type {
   AgentRuntimeSettingsPatch,
   MutateRuntimePolicyInput,
+  NetworkProxyCredentialUpdate,
+  NetworkProxyCredentialTarget,
   RuntimePolicy,
   RuntimePolicyMutation,
+  UpdateNetworkProxyInput,
 } from '../runtime-policy.js';
+import {
+  decodeCredentialVersionBasis,
+  normalizeCredentialSecret,
+} from './credential-vault-codec.js';
 import { WEB_SEARCH_PROVIDERS } from '../web-search.js';
 import {
   assertCanonicalValue,
@@ -74,6 +81,99 @@ export function normalizeRuntimePolicyMutation(value: unknown): MutateRuntimePol
   };
 }
 
+export function normalizeNetworkProxyUpdate(value: unknown): UpdateNetworkProxyInput {
+  const input = exactRecord(value, 'network proxy update', [
+    'expectedPolicyRevision',
+    'expectedCredential',
+    'networkProxy',
+    'credential',
+  ]);
+  const expectedCredential =
+    input.expectedCredential === null
+      ? null
+      : decodeCredentialVersionBasis(input.expectedCredential);
+  if (expectedCredential !== null && expectedCredential.locator.scope !== 'network_proxy') {
+    throw domainError('network proxy update requires a network proxy credential basis');
+  }
+  const credential = normalizeNetworkProxyCredentialUpdate(input.credential);
+  const networkProxy = normalizeNetworkProxy(input.networkProxy);
+  if (!networkProxy.authEnabled && credential.kind !== 'delete') {
+    throw domainError('disabled proxy authentication requires credential deletion');
+  }
+  return {
+    expectedPolicyRevision: revisionValue(
+      input.expectedPolicyRevision,
+      'network proxy expected policy revision',
+    ),
+    expectedCredential,
+    networkProxy,
+    credential,
+  };
+}
+
+function normalizeNetworkProxyCredentialUpdate(value: unknown): NetworkProxyCredentialUpdate {
+  const base = exactRecord(
+    value,
+    'network proxy credential update',
+    ['kind', 'secret', 'expectedTarget'],
+    ['kind'],
+  );
+  switch (base.kind) {
+    case 'keep':
+    case 'delete': {
+      exactRecord(value, `network proxy credential ${base.kind}`, ['kind']);
+      return { kind: base.kind };
+    }
+    case 'replace': {
+      const replacement = exactRecord(
+        value,
+        'network proxy credential replacement',
+        ['kind', 'secret', 'expectedTarget'],
+        ['kind', 'secret'],
+      );
+      return {
+        kind: 'replace',
+        secret: normalizeCredentialSecret(replacement.secret),
+        ...(replacement.expectedTarget === undefined
+          ? {}
+          : {
+              expectedTarget: normalizeNetworkProxyCredentialTarget(replacement.expectedTarget),
+            }),
+      };
+    }
+    default:
+      throw domainError(`network proxy credential update '${String(base.kind)}' is unknown`);
+  }
+}
+
+export function normalizeNetworkProxyCredentialTarget(
+  value: unknown,
+): NetworkProxyCredentialTarget {
+  const item = exactRecord(value, 'network proxy credential target', [
+    'protocol',
+    'host',
+    'port',
+    'username',
+  ]);
+  if (item.protocol !== 'http' && item.protocol !== 'https' && item.protocol !== 'socks5') {
+    throw domainError('network proxy credential target protocol is invalid');
+  }
+  const rawHost = stringValue(item.host, 'network proxy credential target host', 255);
+  if (/[\u0000-\u001f\u007f-\u009f]/.test(rawHost)) {
+    throw domainError('network proxy credential target host must not contain control characters');
+  }
+  const host = rawHost.trim().toLowerCase();
+  if (host.length === 0) {
+    throw domainError('network proxy credential target host must not be empty');
+  }
+  return {
+    protocol: item.protocol,
+    host,
+    port: integerValue(item.port, 'network proxy credential target port', 1, 65_535),
+    username: stringValue(item.username, 'network proxy credential target username', 256),
+  };
+}
+
 function normalizeRuntimePolicy(value: unknown): RuntimePolicy {
   const policy = exactRecord(value, 'runtime policy', [
     'networkProxy',
diff --git a/packages/core/src/settings.ts b/packages/core/src/settings.ts
index 001bde9aa6..b6d2daccec 100644
--- a/packages/core/src/settings.ts
+++ b/packages/core/src/settings.ts
@@ -99,11 +99,46 @@ export interface NetworkProxySettings {
   port: number;
   authEnabled: boolean;
   username: string;
-  password: string;
   bypassList: string[];
   autoBypassDomains: string[];
 }
 
+export interface NetworkProxyCredentialTarget {
+  readonly protocol: ProxyProtocol;
+  readonly host: string;
+  readonly port: number;
+  readonly username: string;
+}
+
+export function networkProxyCredentialTarget(
+  proxy: Pick<NetworkProxySettings, 'protocol' | 'host' | 'port' | 'username'>,
+): NetworkProxyCredentialTarget {
+  return {
+    protocol: proxy.protocol,
+    host: proxy.host.trim().toLowerCase(),
+    port: proxy.port,
+    username: proxy.username,
+  };
+}
+
+export type NetworkProxyCredentialOperation =
+  | {
+      kind: 'replace';
+      secret: string;
+      expectedTarget?: NetworkProxyCredentialTarget;
+    }
+  | { kind: 'delete' };
+
+/** A write-only proxy patch. Credential operations are never persisted. */
+export type NetworkProxySettingsPatch = Partial<NetworkProxySettings> & {
+  credential?: NetworkProxyCredentialOperation;
+};
+
+/** Runtime Host read projection; the saved secret itself never crosses IPC. */
+export interface RuntimeHostNetworkProxySettings extends NetworkProxySettings {
+  readonly passwordConfigured: boolean;
+}
+
 /**
  * Persisted application network settings. Runtime proxy execution uses the
  * separate contract in `settings/network-settings.ts`.
@@ -552,6 +587,12 @@ export interface AppSettings {
   subagents: SubagentSettings;
 }
 
+export interface RuntimeHostAppSettings extends Omit<AppSettings, 'network'> {
+  network: {
+    proxy: RuntimeHostNetworkProxySettings;
+  };
+}
+
 export interface UsageRequestLog {
   id: string;
   ts: number;
@@ -642,6 +683,7 @@ export type SettingsTestResultCode =
   | 'proxy_reachable'
   | 'proxy_disabled'
   | 'proxy_configuration_missing'
+  | 'proxy_credential_missing'
   | 'proxy_timeout'
   | 'proxy_http_error'
   | 'proxy_unreachable'
@@ -653,7 +695,7 @@ export type SettingsTestResultCode =
 
 export type UpdateAppSettingsInput = Partial<{
   network: Partial<{
-    proxy: Partial<NetworkProxySettings>;
+    proxy: NetworkProxySettingsPatch;
   }>;
   botChat: BotChatSettingsPatch;
   usage: Partial<UsageSettings>;
@@ -681,8 +723,8 @@ export interface UpdateAppSettingsWarnings {
   personalization?: PersonalizationSettingsWarning[];
 }
 
-export interface UpdateAppSettingsResult {
-  settings: AppSettings;
+export interface UpdateAppSettingsResult<TSettings extends AppSettings = AppSettings> {
+  settings: TSettings;
   warnings?: UpdateAppSettingsWarnings;
 }
 
@@ -706,7 +748,6 @@ export function createDefaultSettings(): AppSettings {
         port: 7890,
         authEnabled: false,
         username: '',
-        password: '',
         bypassList: ['metaso.cn', 'baidu.com'],
         autoBypassDomains: DEFAULT_PROXY_BYPASS_DOMAINS,
       },
@@ -763,6 +804,15 @@ export function createDefaultSettings(): AppSettings {
 }
 
 export function mergeSettings(current: AppSettings, patch: UpdateAppSettingsInput): AppSettings {
+  const {
+    credential: _credential,
+    password: _legacyPassword,
+    passwordConfigured: _derivedStatus,
+    ...proxyPatch
+  } = (patch.network?.proxy ?? {}) as NetworkProxySettingsPatch & {
+    password?: unknown;
+    passwordConfigured?: unknown;
+  };
   return {
     ...current,
     network: {
@@ -770,7 +820,7 @@ export function mergeSettings(current: AppSettings, patch: UpdateAppSettingsInpu
       ...(patch.network ?? {}),
       proxy: {
         ...current.network.proxy,
-        ...(patch.network?.proxy ?? {}),
+        ...proxyPatch,
       },
     },
     botChat: mergeBotChatSettings(current.botChat, patch.botChat),
diff --git a/packages/core/src/settings/network-settings.ts b/packages/core/src/settings/network-settings.ts
index 51d044d352..25f8ee4aa8 100644
--- a/packages/core/src/settings/network-settings.ts
+++ b/packages/core/src/settings/network-settings.ts
@@ -68,7 +68,7 @@ export const NETWORK_DEFAULTS: RuntimeNetworkSettings = {
   preferIpv4: false,
 };
 
-export interface TestProxySettings extends ProxySettings {
+export interface TestProxySettings extends Omit<ProxySettings, 'password'> {
   authEnabled?: boolean;
 }
 
diff --git a/packages/runtime-host/src/__tests__/protocol.test.ts b/packages/runtime-host/src/__tests__/protocol.test.ts
index 3bbe698872..1989f4b504 100644
--- a/packages/runtime-host/src/__tests__/protocol.test.ts
+++ b/packages/runtime-host/src/__tests__/protocol.test.ts
@@ -251,6 +251,21 @@ describe('Runtime Host bootstrap protocol', () => {
     assert.ok(RUNTIME_HOST_COMPATIBILITY_EPOCH > 50);
   });
 
+  test('publishes a new compatibility epoch for compound proxy updates', () => {
+    assert.ok(RUNTIME_HOST_COMPATIBILITY_EPOCH > 83);
+  });
+
+  test('publishes a new compatibility epoch for bound configuration credentials', () => {
+    assert.ok(RUNTIME_HOST_COMPATIBILITY_EPOCH > 84);
+  });
+
+  test('publishes a new compatibility epoch for explicit proxy credential updates', () => {
+    // Epoch 87 predates the Host-owned proxy credential mutation and its
+    // target-bound transfer result. Older peers cannot safely exchange these
+    // shapes, so the merged PR must advance the handshake boundary.
+    assert.ok(RUNTIME_HOST_COMPATIBILITY_EPOCH > 87);
+  });
+
   test('publishes a new compatibility epoch for the removed execution.inspect.resolve operation', () => {
     // Epoch 63 peers still know execution.inspect.resolve and would send it
     // only to fail mid-connection now that it is gone, so its removal must
@@ -899,6 +914,96 @@ describe('Runtime Host bootstrap protocol', () => {
     );
   });
 
+  test('keeps connection credential transfer bound to an exact Host target', () => {
+    const locator = {
+      scope: 'connection',
+      connectionId: '00000000-0000-4000-8000-000000000001',
+      kind: 'api_key',
+    } as const;
+    const expectedConnection = {
+      connectionId: locator.connectionId,
+      revision: 4,
+      slug: 'deepseek-main',
+      providerType: 'deepseek' as const,
+      effectiveBaseUrl: 'https://api.deepseek.com/',
+    };
+    const setInput = {
+      locator,
+      expected: null,
+      expectedConnection,
+      secret: 'bound-secret',
+    };
+    assert.deepEqual(
+      RUNTIME_POLICY_OPERATION_SPECS['credential.vault.set'].decodeInput(setInput),
+      setInput,
+    );
+    const exportInput = { locator, expectedConnection };
+    assert.deepEqual(
+      HOST_OPERATION_SPECS['configuration.credentials.export'].decodeInput(exportInput),
+      exportInput,
+    );
+    assert.deepEqual(
+      HOST_OPERATION_SPECS['configuration.credentials.export'].decodeOutput({
+        credential: null,
+        connectionStale: {
+          expected: { connectionId: locator.connectionId, revision: 4 },
+          actual: { connectionId: locator.connectionId, revision: 5 },
+        },
+      }),
+      {
+        credential: null,
+        connectionStale: {
+          expected: { connectionId: locator.connectionId, revision: 4 },
+          actual: { connectionId: locator.connectionId, revision: 5 },
+        },
+      },
+    );
+    assert.throws(
+      () =>
+        HOST_OPERATION_SPECS['configuration.credentials.export'].decodeInput({
+          locator: { scope: 'network_proxy', kind: 'password' },
+          expectedConnection,
+        }),
+      isInvalidFrame,
+    );
+  });
+
+  test('exports a proxy credential with its Host-read target binding', () => {
+    const locator = { scope: 'network_proxy', kind: 'password' } as const;
+    const result = {
+      credential: {
+        locator,
+        secretBase64: Buffer.from('proxy-secret').toString('base64'),
+        proxyTarget: {
+          protocol: 'https' as const,
+          host: 'proxy.example',
+          port: 8443,
+          username: 'proxy-user',
+        },
+      },
+    };
+
+    assert.deepEqual(
+      HOST_OPERATION_SPECS['configuration.credentials.export'].decodeOutput(result),
+      result,
+    );
+    assert.throws(
+      () =>
+        HOST_OPERATION_SPECS['configuration.credentials.export'].decodeOutput({
+          credential: {
+            locator: {
+              scope: 'connection',
+              connectionId: '00000000-0000-4000-8000-000000000001',
+              kind: 'api_key',
+            },
+            secretBase64: Buffer.from('connection-secret').toString('base64'),
+            proxyTarget: result.credential.proxyTarget,
+          },
+        }),
+      isInvalidFrame,
+    );
+  });
+
   test('keeps the connection update model limit aligned with the catalog', () => {
     const updateConnection = RUNTIME_POLICY_OPERATION_SPECS['connection.catalog.update'];
     const enabledModelIds = Array.from(
@@ -982,6 +1087,107 @@ describe('Runtime Host bootstrap protocol', () => {
     );
   });
 
+  test('rejects password overrides on network proxy tests', () => {
+    assert.throws(
+      () =>
+        HOST_OPERATION_SPECS['network-proxy.test'].decodeInput({
+          password: 'must-not-cross-wire',
+        }),
+      isInvalidFrame,
+    );
+  });
+
+  test('keeps compound proxy credentials write-only on the protocol', () => {
+    const operation = RUNTIME_POLICY_OPERATION_SPECS['runtime.policy.network-proxy.update'];
+    const input = {
+      expectedPolicyRevision: 4,
+      expectedCredential: null,
+      networkProxy: {
+        enabled: true,
+        protocol: 'http' as const,
+        host: '127.0.0.1',
+        port: 7897,
+        authEnabled: true,
+        username: 'proxy-user',
+        bypassList: ['localhost'],
+        autoBypassDomains: ['127.0.0.1'],
+      },
+      credential: {
+        kind: 'replace' as const,
+        secret: 'write-only-secret',
+        expectedTarget: {
+          protocol: 'http' as const,
+          host: '127.0.0.1',
+          port: 7897,
+          username: 'proxy-user',
+        },
+      },
+    };
+    assert.deepEqual(operation.decodeInput(input), input);
+    assert.deepEqual(
+      operation.decodeOutput({
+        kind: 'committed',
+        revision: 5,
+        credentialStatus: {
+          locator: { scope: 'network_proxy', kind: 'password' },
+          configured: true,
+          credentialId: '00000000-0000-4000-8000-000000000001',
+          revision: 2,
+          updatedAt: 1,
+        },
+      }),
+      {
+        kind: 'committed',
+        revision: 5,
+        credentialStatus: {
+          locator: { scope: 'network_proxy', kind: 'password' },
+          configured: true,
+          credentialId: '00000000-0000-4000-8000-000000000001',
+          revision: 2,
+          updatedAt: 1,
+        },
+      },
+    );
+    assert.deepEqual(
+      operation.decodeOutput({
+        kind: 'proxy_target_mismatch',
+        expected: input.credential.expectedTarget,
+        actual: {
+          protocol: 'https',
+          host: 'proxy.example',
+          port: 8443,
+          username: 'other-user',
+        },
+      }),
+      {
+        kind: 'proxy_target_mismatch',
+        expected: input.credential.expectedTarget,
+        actual: {
+          protocol: 'https',
+          host: 'proxy.example',
+          port: 8443,
+          username: 'other-user',
+        },
+      },
+    );
+    assert.throws(
+      () =>
+        operation.decodeOutput({
+          kind: 'committed',
+          revision: 5,
+          credentialStatus: {
+            locator: { scope: 'network_proxy', kind: 'password' },
+            configured: true,
+            credentialId: '00000000-0000-4000-8000-000000000001',
+            revision: 2,
+            updatedAt: 1,
+            secret: 'must-not-cross-wire',
+          },
+        }),
+      isInvalidFrame,
+    );
+  });
+
   test('encodes maximum legal tool output as one bounded frame without identity loss', () => {
     const chunks = [
       ['CJK', '界'.repeat(TOOL_OUTPUT_DELTA_MAX_CHARS)],
diff --git a/packages/runtime-host/src/__tests__/runtime-policy-coordinator.test.ts b/packages/runtime-host/src/__tests__/runtime-policy-coordinator.test.ts
index b560553f37..84231b07ea 100644
--- a/packages/runtime-host/src/__tests__/runtime-policy-coordinator.test.ts
+++ b/packages/runtime-host/src/__tests__/runtime-policy-coordinator.test.ts
@@ -29,7 +29,10 @@ import type {
   ConnectionCatalogSnapshot,
   CredentialLocator,
 } from '@maka/core/runtime-policy';
-import { REQUEST_BODY_OVERLAY_MAX_BYTES } from '@maka/core/runtime-policy';
+import {
+  connectionCredentialTarget,
+  REQUEST_BODY_OVERLAY_MAX_BYTES,
+} from '@maka/core/runtime-policy';
 import { resolveConnectionModelCatalog } from '@maka/core/model-catalog';
 import { FAKE_ASK_USER_QUESTION_PROMPT, FakeBackend } from '@maka/runtime/test-only/fake-backend';
 import { type MakaToolContext } from '@maka/runtime/tool-runtime';
@@ -467,6 +470,79 @@ test('projects runtime policy CAS results without returning the committed snapsh
   });
 });
 
+test('two clients cannot recreate a proxy credential after authentication is disabled', async () => {
+  await withCoordinator(async ({ coordinator, stores }) => {
+    const initial = await stores.runtimePolicy.getSnapshot();
+    const configured = await coordinator.handlers['runtime.policy.network-proxy.update'](
+      {
+        expectedPolicyRevision: initial.revision,
+        expectedCredential: null,
+        networkProxy: {
+          ...initial.policy.networkProxy,
+          enabled: true,
+          authEnabled: true,
+          username: 'proxy-user',
+        },
+        credential: { kind: 'replace', secret: 'initial-secret' },
+      },
+      context,
+    );
+    assert.equal(configured.ok, true);
+    if (!configured.ok || configured.result.kind !== 'committed') return;
+    assert.equal(configured.result.credentialStatus.configured, true);
+    if (!configured.result.credentialStatus.configured) return;
+    assert.equal(JSON.stringify(configured).includes('initial-secret'), false);
+    const sharedCredentialBasis = {
+      locator: configured.result.credentialStatus.locator,
+      credentialId: configured.result.credentialStatus.credentialId,
+      revision: configured.result.credentialStatus.revision,
+    };
+    const configuredPolicy = await stores.runtimePolicy.getSnapshot();
+
+    const disabled = await coordinator.handlers['runtime.policy.network-proxy.update'](
+      {
+        expectedPolicyRevision: configured.result.revision,
+        expectedCredential: sharedCredentialBasis,
+        networkProxy: {
+          ...configuredPolicy.policy.networkProxy,
+          authEnabled: false,
+          username: '',
+        },
+        credential: { kind: 'delete' },
+      },
+      context,
+    );
+    assert.equal(disabled.ok, true);
+    if (!disabled.ok || disabled.result.kind !== 'committed') return;
+
+    // Client A prepared its request from the shared pre-disable basis, but its
+    // Host command arrives after client B's disable command has committed.
+    const stale = await coordinator.handlers['runtime.policy.network-proxy.update'](
+      {
+        expectedPolicyRevision: configured.result.revision,
+        expectedCredential: sharedCredentialBasis,
+        networkProxy: configuredPolicy.policy.networkProxy,
+        credential: { kind: 'replace', secret: 'must-not-return' },
+      },
+      context,
+    );
+    assert.equal(stale.ok, true);
+    if (!stale.ok) return;
+    assert.ok(
+      stale.result.kind === 'revision_conflict' || stale.result.kind === 'credential_stale',
+    );
+
+    const finalPolicy = await stores.runtimePolicy.getSnapshot();
+    const finalCredential = await stores.credentialVault.getStatus({
+      scope: 'network_proxy',
+      kind: 'password',
+    });
+    assert.equal(finalPolicy.policy.networkProxy.authEnabled, false);
+    assert.equal(finalCredential.kind, 'status');
+    if (finalCredential.kind === 'status') assert.equal(finalCredential.status.configured, false);
+  });
+});
+
 test('rejects a Host-invalid shell preference before it reaches durable policy', async () => {
   await withCoordinator(async ({ stores }) => {
     const coordinator = new HostRuntimePolicyCoordinator(
@@ -812,6 +888,94 @@ test('returns connection_not_found when deleting a credential after its connecti
   });
 });
 
+test('two Host clients cannot write an imported credential after retargeting its Connection', async () => {
+  await withCoordinator(async ({ coordinator, stores }) => {
+    const created = await stores.connectionCatalog.create({
+      expectedCatalogRevision: 0,
+      connection: {
+        slug: 'bound-import',
+        name: 'Bound import',
+        providerType: 'openai',
+        enabled: true,
+        enabledModelIds: [],
+      },
+    });
+    assert.equal(created.kind, 'committed');
+    if (created.kind !== 'committed') return;
+    const connection = created.snapshot.connections[0];
+    assert.ok(connection);
+    if (!connection) return;
+    const locator: CredentialLocator = {
+      scope: 'connection',
+      connectionId: connection.connectionId,
+      kind: 'api_key',
+    };
+    const seeded = await stores.credentialVault.set({
+      locator,
+      expected: null,
+      secret: 'target-secret',
+    });
+    assert.equal(seeded.kind, 'committed');
+    if (seeded.kind !== 'committed') return;
+    const status = seeded.snapshot.entries.find((entry) => entry.locator.scope === 'connection');
+    assert.ok(status?.configured);
+    if (!status?.configured) return;
+
+    // Client A observed this exact target and credential generation.
+    const expectedConnection = connectionCredentialTarget(connection);
+    const expectedCredential = {
+      credentialId: status.credentialId,
+      revision: status.revision,
+    };
+
+    // Client B wins the Host mutation lane and retargets the same entity.
+    const moved = await coordinator.handlers['connection.catalog.update'](
+      {
+        expected: {
+          connectionId: connection.connectionId,
+          revision: connection.revision,
+        },
+        changes: {
+          name: connection.name,
+          baseUrl: 'https://target-relay.example/v1',
+          enabled: connection.enabled,
+          enabledModelIds: connection.enabledModelIds,
+          relayModelProfiles: null,
+        },
+      },
+      context,
+    );
+    assert.equal(moved.ok, true);
+    if (!moved.ok || moved.result.kind !== 'committed') return;
+
+    const stale = await coordinator.handlers['credential.vault.set'](
+      {
+        locator,
+        expected: expectedCredential,
+        expectedConnection,
+        secret: 'source-import-secret',
+      },
+      context,
+    );
+
+    assert.deepEqual(stale, {
+      ok: true,
+      result: {
+        kind: 'connection_stale',
+        expected: {
+          connectionId: connection.connectionId,
+          revision: connection.revision,
+        },
+        actual: moved.result.connection,
+      },
+    });
+    assert.equal(
+      (await stores.operations.exportCredentialMaterial(locator))?.secret,
+      'target-secret',
+    );
+  });
+});
+
 test('a fully profiled relay catalog paginates with profiles riding per item', async () => {
   await withCoordinator(async ({ coordinator, stores }) => {
     // Every claim in one header table used to be what made a long catalog
diff --git a/packages/runtime-host/src/protocol/configuration.ts b/packages/runtime-host/src/protocol/configuration.ts
index 1da6c4f375..a23b53583b 100644
--- a/packages/runtime-host/src/protocol/configuration.ts
+++ b/packages/runtime-host/src/protocol/configuration.ts
@@ -19,7 +19,13 @@
 
 import {
   decodeCredentialLocator,
+  decodeConnectionCredentialTarget,
+  decodeConnectionVersionBasis,
+  normalizeNetworkProxyCredentialTarget,
   REQUEST_HEADERS_MAX_BYTES,
+  type ConnectionCredentialTarget,
+  type ConnectionVersionBasis,
+  type NetworkProxyCredentialTarget,
   type CredentialLocator,
 } from '@maka/core/runtime-policy';
 import {
@@ -43,13 +49,19 @@ const ERRORS = [
 
 export interface ConfigurationCredentialExportInput {
   readonly locator: CredentialLocator;
+  readonly expectedConnection?: ConnectionCredentialTarget;
 }
 
 export interface ConfigurationCredentialExportResult {
   readonly credential: {
     readonly locator: CredentialLocator;
     readonly secretBase64: string;
+    readonly proxyTarget?: NetworkProxyCredentialTarget;
   } | null;
+  readonly connectionStale?: {
+    readonly expected: ConnectionVersionBasis;
+    readonly actual: ConnectionVersionBasis | null;
+  };
 }
 
 export const CONFIGURATION_OPERATION_SPECS = {
@@ -69,24 +81,62 @@ export const CONFIGURATION_OPERATION_SPECS = {
 function decodeConfigurationCredentialExportInput(
   value: unknown,
 ): ConfigurationCredentialExportInput {
-  const input = requireExactRecord(value, 'configuration credential export input', ['locator']);
-  return { locator: decodeLocator(input.locator) };
+  const input = requireShapedRecord(
+    value,
+    'configuration credential export input',
+    ['locator'],
+    ['expectedConnection'],
+  );
+  const locator = decodeLocator(input.locator);
+  const expectedConnection =
+    input.expectedConnection === undefined
+      ? undefined
+      : decodeDomainValue(() => decodeConnectionCredentialTarget(input.expectedConnection));
+  if (expectedConnection && locator.scope !== 'connection') {
+    throw invalidProtocolFrame('Only connection credential exports accept a target basis');
+  }
+  return {
+    locator,
+    ...(expectedConnection === undefined ? {} : { expectedConnection }),
+  };
 }
 
 function decodeConfigurationCredentialExportResult(
   value: unknown,
 ): ConfigurationCredentialExportResult {
-  const result = requireExactRecord(value, 'configuration credential export result', [
-    'credential',
-  ]);
-  if (result.credential === null) return { credential: null };
+  const result = requireShapedRecord(
+    value,
+    'configuration credential export result',
+    ['credential'],
+    ['connectionStale'],
+  );
+  const connectionStale =
+    result.connectionStale === undefined
+      ? undefined
+      : decodeConnectionStale(result.connectionStale);
+  if (connectionStale && result.credential !== null) {
+    throw invalidProtocolFrame('A stale connection export must not include credential material');
+  }
+  if (result.credential === null) {
+    return {
+      credential: null,
+      ...(connectionStale === undefined ? {} : { connectionStale }),
+    };
+  }
   const entry = requireShapedRecord(
     result.credential,
     'exported configuration credential',
     ['locator', 'secretBase64'],
-    [],
+    ['proxyTarget'],
   );
   const locator = decodeLocator(entry.locator);
+  const proxyTarget =
+    entry.proxyTarget === undefined
+      ? undefined
+      : decodeDomainValue(() => normalizeNetworkProxyCredentialTarget(entry.proxyTarget));
+  if (proxyTarget && locator.scope !== 'network_proxy') {
+    throw invalidProtocolFrame('Only proxy credentials may carry a proxy target');
+  }
   const maxBytes =
     locator.scope === 'connection' && locator.kind === 'request_headers'
       ? REQUEST_HEADERS_MAX_BYTES
@@ -95,12 +145,39 @@ function decodeConfigurationCredentialExportResult(
     credential: {
       locator,
       secretBase64: decodeCredentialSecretBase64(entry.secretBase64, maxBytes),
+      ...(proxyTarget === undefined ? {} : { proxyTarget }),
     },
+    ...(connectionStale === undefined ? {} : { connectionStale }),
   };
   requireEncodedByteLimit(decoded, 'configuration credential export result', RESULT_MAX_BYTES);
   return decoded;
 }
 
+function decodeConnectionStale(value: unknown): {
+  expected: ConnectionVersionBasis;
+  actual: ConnectionVersionBasis | null;
+} {
+  const stale = requireExactRecord(value, 'configuration credential stale connection', [
+    'expected',
+    'actual',
+  ]);
+  return {
+    expected: decodeDomainValue(() => decodeConnectionVersionBasis(stale.expected)),
+    actual:
+      stale.actual === null
+        ? null
+        : decodeDomainValue(() => decodeConnectionVersionBasis(stale.actual)),
+  };
+}
+
+function decodeDomainValue<T>(decode: () => T): T {
+  try {
+    return decode();
+  } catch {
+    throw invalidProtocolFrame('Invalid configuration credential connection basis');
+  }
+}
+
 function decodeCredentialSecretBase64(value: unknown, maxBytes: number): string {
   const encoded = requireUtf8String(
     value,
diff --git a/packages/runtime-host/src/protocol/index.ts b/packages/runtime-host/src/protocol/index.ts
index 7b7c8a2cf8..bc5f27e602 100644
--- a/packages/runtime-host/src/protocol/index.ts
+++ b/packages/runtime-host/src/protocol/index.ts
@@ -100,7 +100,11 @@ export const RUNTIME_HOST_REGISTRATION_SCHEMA_VERSION = 1 as const;
 export const RUNTIME_HOST_PROTOCOL_VERSION = 0 as const;
 // Increment when the same protocol version no longer guarantees safe Client-Host
 // interoperability. Mismatches are rejected before domain commands are admitted.
-export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 92 as const;
+export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 93 as const;
+// 93: Configuration credential transfer binds proxy destinations and
+// Connection credentials to exact Host-owned targets before secret access.
+// Proxy policy and credentials commit through one recoverable Host command;
+// older peers can split the writes and violate the shared credential basis.
 // 92: Owners can query their complete pending Session Turn-request inbox.
 // 91: Host status publishes the live Direct peer endpoint so newly issued
 // connection invitations do not preserve stale startup routes.
diff --git a/packages/runtime-host/src/protocol/network-proxy.ts b/packages/runtime-host/src/protocol/network-proxy.ts
index ed5f2b1187..0fb0e1818a 100644
--- a/packages/runtime-host/src/protocol/network-proxy.ts
+++ b/packages/runtime-host/src/protocol/network-proxy.ts
@@ -29,7 +29,6 @@ import {
 import { invalidProtocolFrame } from './errors.js';
 import { defineOperation } from './operation-spec.js';
 
-const SECRET_MAX_BYTES = 16 * 1024;
 const RESULT_MAX_BYTES = 8 * 1024;
 const ERRORS = [
   'host_not_ready',
@@ -41,7 +40,6 @@ const ERRORS = [
 
 export interface NetworkProxyTestInput {
   readonly networkProxy?: RuntimePolicy['networkProxy'];
-  readonly password?: string;
   readonly url?: string;
   readonly timeoutMs?: number;
 }
@@ -67,17 +65,12 @@ function decodeNetworkProxyTestInput(value: unknown): NetworkProxyTestInput {
     value,
     'network proxy test input',
     [],
-    ['networkProxy', 'password', 'url', 'timeoutMs'],
+    ['networkProxy', 'url', 'timeoutMs'],
   );
   return {
     ...(input.networkProxy === undefined
       ? {}
       : { networkProxy: decodeNetworkProxy(input.networkProxy) }),
-    ...(input.password === undefined
-      ? {}
-      : {
-          password: requireUtf8String(input.password, 'network proxy password', SECRET_MAX_BYTES),
-        }),
     ...(input.url === undefined ? {} : { url: decodeProbeUrl(input.url) }),
     ...(input.timeoutMs === undefined
       ? {}
diff --git a/packages/runtime-host/src/protocol/operations.ts b/packages/runtime-host/src/protocol/operations.ts
index f826da5017..0a03ab137e 100644
--- a/packages/runtime-host/src/protocol/operations.ts
+++ b/packages/runtime-host/src/protocol/operations.ts
@@ -298,6 +298,7 @@ export const REMOTE_OWNER_OPERATION_GRANTS = Object.freeze([
   'queue.entry.update',
   'queue.retract',
   'runtime.policy.mutate',
+  'runtime.policy.network-proxy.update',
   'runtime.policy.query',
   'runtime.resource.controller.acquire',
   'runtime.resource.controller.control',
diff --git a/packages/runtime-host/src/protocol/runtime-policy.ts b/packages/runtime-host/src/protocol/runtime-policy.ts
index b121bb5bc4..7f7f877f1b 100644
--- a/packages/runtime-host/src/protocol/runtime-policy.ts
+++ b/packages/runtime-host/src/protocol/runtime-policy.ts
@@ -41,6 +41,8 @@ import {
   normalizeDeleteCredentialInput,
   normalizeRemoveCatalogConnectionInput,
   normalizeOptionalRequestBodyOverlay,
+  normalizeNetworkProxyUpdate,
+  normalizeNetworkProxyCredentialTarget,
   normalizeRequestHeaderUpdates,
   normalizeRuntimePolicyMutation,
   normalizeSetCredentialInput,
@@ -59,10 +61,12 @@ import {
   type CredentialVersionBasis,
   type DeleteCredentialInput,
   type MutateRuntimePolicyInput,
+  type NetworkProxyCredentialTarget,
   type RemoveCatalogConnectionInput,
   type RequestHeaderUpdate,
   type RevisionConflict,
   type RuntimePolicySnapshot,
+  type UpdateNetworkProxyInput,
   type SetCredentialInput,
   type SetDefaultConnectionTargetInput,
   type UpdateCatalogConnectionInput,
@@ -107,6 +111,20 @@ export type RuntimePolicyMutateInput = MutateRuntimePolicyInput;
 export type RuntimePolicyMutateResult =
   | { readonly kind: 'committed'; readonly revision: number }
   | RevisionConflict;
+export type RuntimePolicyNetworkProxyUpdateInput = UpdateNetworkProxyInput;
+export type RuntimePolicyNetworkProxyUpdateResult =
+  | {
+      readonly kind: 'committed';
+      readonly revision: number;
+      readonly credentialStatus: CredentialStatus;
+    }
+  | RevisionConflict
+  | {
+      readonly kind: 'proxy_target_mismatch';
+      readonly expected: NetworkProxyCredentialTarget;
+      readonly actual: NetworkProxyCredentialTarget;
+    }
+  | CredentialStale;
 
 export type ConnectionCatalogCursor =
   | { readonly connectionIndex: number; readonly part: 'connection' }
@@ -244,6 +262,7 @@ export type CredentialVaultQueryResult =
 export type SetCredentialResult =
   | CredentialCommitted
   | { readonly kind: 'connection_not_found' }
+  | ConnectionStale
   | CredentialStale;
 export type DeleteCredentialResult =
   | CredentialCommitted
@@ -304,6 +323,17 @@ export const RUNTIME_POLICY_OPERATION_SPECS = {
     decodeInput: decodeRuntimePolicyMutation,
     decodeOutput: decodeRuntimePolicyMutationResult,
   }),
+  'runtime.policy.network-proxy.update': defineOperation<
+    RuntimePolicyNetworkProxyUpdateInput,
+    RuntimePolicyNetworkProxyUpdateResult,
+    (typeof MUTATION_ERRORS)[number]
+  >({
+    mode: 'command',
+    availability: 'ready',
+    errors: MUTATION_ERRORS,
+    decodeInput: decodeRuntimePolicyNetworkProxyUpdate,
+    decodeOutput: decodeRuntimePolicyNetworkProxyUpdateResult,
+  }),
   'connection.catalog.query': defineOperation<
     ConnectionCatalogQueryInput,
     ConnectionCatalogQueryResult,
@@ -449,6 +479,51 @@ function decodeRuntimePolicyMutationResult(value: unknown): RuntimePolicyMutateR
   return revisionConflict(item, 'runtime policy mutation result');
 }
 
+function decodeRuntimePolicyNetworkProxyUpdate(
+  value: unknown,
+): RuntimePolicyNetworkProxyUpdateInput {
+  const input = decodeDomain(() => normalizeNetworkProxyUpdate(value));
+  if (
+    input.credential.kind === 'replace' &&
+    Buffer.byteLength(input.credential.secret, 'utf8') > CREDENTIAL_SECRET_MAX_BYTES
+  ) {
+    throw invalidProtocolFrame('Invalid network proxy credential secret');
+  }
+  return input;
+}
+
+function decodeRuntimePolicyNetworkProxyUpdateResult(
+  value: unknown,
+): RuntimePolicyNetworkProxyUpdateResult {
+  const item = requireRecord(value, 'network proxy update result');
+  if (item.kind === 'committed') {
+    const committed = requireExactRecord(item, 'network proxy update committed result', [
+      'kind',
+      'revision',
+      'credentialStatus',
+    ]);
+    return {
+      kind: 'committed',
+      revision: revision(committed.revision, 'runtime policy revision'),
+      credentialStatus: decodeDomain(() => decodeCredentialStatus(committed.credentialStatus)),
+    };
+  }
+  if (item.kind === 'credential_stale') return credentialStale(item);
+  if (item.kind === 'proxy_target_mismatch') {
+    const mismatch = requireExactRecord(item, 'network proxy target mismatch', [
+      'kind',
+      'expected',
+      'actual',
+    ]);
+    return {
+      kind: 'proxy_target_mismatch',
+      expected: decodeDomain(() => normalizeNetworkProxyCredentialTarget(mismatch.expected)),
+      actual: decodeDomain(() => normalizeNetworkProxyCredentialTarget(mismatch.actual)),
+    };
+  }
+  return revisionConflict(item, 'network proxy update result');
+}
+
 function decodeCatalogQueryInput(value: unknown): ConnectionCatalogQueryInput {
   const item = requireRecord(value, 'connection catalog query input');
   if (item.kind === 'start') {
@@ -886,6 +961,7 @@ function decodeSetCredentialResult(value: unknown): SetCredentialResult {
     requireExactRecord(item, 'credential connection not found result', ['kind']);
     return { kind: 'connection_not_found' };
   }
+  if (item.kind === 'connection_stale') return connectionStale(item);
   return credentialStale(item);
 }
 
diff --git a/packages/runtime-host/src/server/configuration-coordinator.ts b/packages/runtime-host/src/server/configuration-coordinator.ts
index 143f0b5a69..0f6bd0963c 100644
--- a/packages/runtime-host/src/server/configuration-coordinator.ts
+++ b/packages/runtime-host/src/server/configuration-coordinator.ts
@@ -34,11 +34,30 @@ export class HostConfigurationCoordinator {
     input: ConfigurationCredentialExportInput,
   ): Promise<OperationOutcome<'configuration.credentials.export'>> {
     try {
-      const material = await this.policy.exportCredentialMaterial(input.locator);
+      const exported = input.expectedConnection
+        ? await this.policy.exportCredentialMaterial(input.locator, input.expectedConnection)
+        : {
+            kind: 'exported' as const,
+            material: await this.policy.exportCredentialMaterial(input.locator),
+          };
+      if (exported.kind === 'connection_stale') {
+        return {
+          ok: true,
+          result: {
+            credential: null,
+            connectionStale: {
+              expected: exported.expected,
+              actual: exported.actual,
+            },
+          },
+        };
+      }
+      const material = exported.material;
       const credential = material
         ? {
             locator: material.locator,
             secretBase64: Buffer.from(material.secret, 'utf8').toString('base64'),
+            ...(material.proxyTarget === undefined ? {} : { proxyTarget: material.proxyTarget }),
           }
         : null;
       return { ok: true, result: { credential } };
diff --git a/packages/runtime-host/src/server/network-proxy-coordinator.ts b/packages/runtime-host/src/server/network-proxy-coordinator.ts
index f87a4cfe4b..19008b95f6 100644
--- a/packages/runtime-host/src/server/network-proxy-coordinator.ts
+++ b/packages/runtime-host/src/server/network-proxy-coordinator.ts
@@ -40,7 +40,6 @@ export class HostNetworkProxyCoordinator {
     try {
       const resolved = await this.policy.resolveNetworkProxyExecution({
         ...(input.networkProxy ? { networkProxy: input.networkProxy } : {}),
-        ...(input.password ? { secretOverride: input.password } : {}),
       });
       if (resolved.kind === 'credential_not_configured') {
         return {
diff --git a/packages/runtime-host/src/server/runtime-policy-coordinator.ts b/packages/runtime-host/src/server/runtime-policy-coordinator.ts
index 2133cf9bfe..aec72b6ffb 100644
--- a/packages/runtime-host/src/server/runtime-policy-coordinator.ts
+++ b/packages/runtime-host/src/server/runtime-policy-coordinator.ts
@@ -97,6 +97,7 @@ export class HostRuntimePolicyCoordinator {
   readonly handlers: RuntimePolicyOperationHandlerMap = {
     'runtime.policy.query': () => this.#queryPolicy(),
     'runtime.policy.mutate': (input) => this.#mutatePolicy(input),
+    'runtime.policy.network-proxy.update': (input) => this.#updateNetworkProxy(input),
     'connection.catalog.query': (input) => this.#queryCatalog(input),
     'connection.catalog.create': (input) => this.#createConnection(input),
     'connection.catalog.update': (input) => this.#updateConnection(input),
@@ -145,6 +146,33 @@ export class HostRuntimePolicyCoordinator {
     });
   }
 
+  async #updateNetworkProxy(
+    input: Parameters<RuntimePolicyOperationHandlerMap['runtime.policy.network-proxy.update']>[0],
+  ): Promise<OperationOutcome<'runtime.policy.network-proxy.update'>> {
+    return this.#storeMutation(async () => {
+      try {
+        await this.validateMutation({
+          expectedRevision: input.expectedPolicyRevision,
+          operation: { kind: 'set_network_proxy', value: input.networkProxy },
+        });
+      } catch (error) {
+        throw new RuntimePolicyStoreError(
+          'invalid_policy_input',
+          'Network proxy update failed Host validation',
+          { cause: error },
+        );
+      }
+      const result = await this.#stores.operations.updateNetworkProxy(input);
+      return result.kind === 'committed'
+        ? {
+            kind: 'committed' as const,
+            revision: result.snapshot.revision,
+            credentialStatus: result.credentialStatus,
+          }
+        : result;
+    });
+  }
+
   async #queryCatalog(
     input: ConnectionCatalogQueryInput,
   ): Promise<OperationOutcome<'connection.catalog.query'>> {
@@ -241,7 +269,11 @@ export class HostRuntimePolicyCoordinator {
   ): Promise<OperationOutcome<'credential.vault.set'>> {
     return this.#storeMutation(async () => {
       const result = await this.#stores.credentialVault.set(input);
-      if (result.kind === 'connection_not_found' || result.kind === 'credential_stale') {
+      if (
+        result.kind === 'connection_not_found' ||
+        result.kind === 'connection_stale' ||
+        result.kind === 'credential_stale'
+      ) {
         return result;
       }
       const status = result.snapshot.entries.find((entry) =>
@@ -259,6 +291,9 @@ export class HostRuntimePolicyCoordinator {
   ): Promise<OperationOutcome<'credential.vault.delete'>> {
     return this.#storeMutation(async () => {
       const result = await this.#stores.credentialVault.delete(input);
+      if (result.kind === 'connection_stale') {
+        throw invariantFailure('Credential deletion returned an impossible connection conflict');
+      }
       if (result.kind === 'connection_not_found' || result.kind === 'credential_stale') {
         return result;
       }
diff --git a/packages/storage/src/__tests__/runtime-policy-stores.test.ts b/packages/storage/src/__tests__/runtime-policy-stores.test.ts
index d6a5ae1d33..2c3b428b53 100644
--- a/packages/storage/src/__tests__/runtime-policy-stores.test.ts
+++ b/packages/storage/src/__tests__/runtime-policy-stores.test.ts
@@ -2122,6 +2122,87 @@ describe('runtime policy stores', () => {
     });
   });
 
+  test('a bound connection credential write rejects revision, provider, and endpoint drift', async () => {
+    await withInteractiveOwner(async ({ stores }) => {
+      const connection = await createConnection(
+        stores,
+        0,
+        connectionDraft('bound-import', 'openai', 'Bound import'),
+      );
+      const locator = connectionCredential(connection, 'api_key');
+      const seeded = await stores.credentialVault.set({
+        locator,
+        expected: null,
+        secret: 'existing-target-secret',
+      });
+      assert.equal(seeded.kind, 'committed');
+      if (seeded.kind !== 'committed') return;
+      const status = await getCredentialStatus(stores.credentialVault, locator);
+      const sourceTarget = {
+        ...connectionBasis(connection),
+        slug: connection.slug,
+        providerType: connection.providerType,
+        effectiveBaseUrl: new URL(PROVIDER_REGISTRY.openai.baseUrl).toString(),
+      };
+
+      const moved = await stores.connectionCatalog.update({
+        expected: connectionBasis(connection),
+        changes: {
+          name: connection.name,
+          baseUrl: 'https://target-relay.example/v1',
+          enabled: connection.enabled,
+          enabledModelIds: connection.enabledModelIds,
+        },
+      });
+      assert.equal(moved.kind, 'committed');
+      if (moved.kind !== 'committed') return;
+      const current = moved.snapshot.connections.find(
+        (item) => item.connectionId === connection.connectionId,
+      );
+      assert.ok(current);
+      if (!current) return;
+
+      const staleRevision = await stores.credentialVault.set({
+        locator,
+        expected: credentialExpectation(status),
+        expectedConnection: sourceTarget,
+        secret: 'must-not-cross-targets',
+      } as never);
+      assert.deepEqual(staleRevision, {
+        kind: 'connection_stale',
+        expected: connectionBasis(connection),
+        actual: connectionBasis(current),
+      });
+      assert.deepEqual(await stores.operations.exportCredentialMaterial(locator, sourceTarget), {
+        kind: 'connection_stale',
+        expected: connectionBasis(connection),
+        actual: connectionBasis(current),
+      });
+
+      for (const expectedConnection of [
+        { ...sourceTarget, ...connectionBasis(current) },
+        { ...sourceTarget, ...connectionBasis(current), providerType: 'deepseek' },
+      ]) {
+        const mismatch = await stores.credentialVault.set({
+          locator,
+          expected: credentialExpectation(status),
+          expectedConnection,
+          secret: 'must-not-cross-targets',
+        } as never);
+        assert.deepEqual(mismatch, {
+          kind: 'connection_stale',
+          expected: connectionBasis(current),
+          actual: connectionBasis(current),
+        });
+      }
+
+      assert.equal(
+        (await stores.operations.exportCredentialMaterial(locator))?.secret,
+        'existing-target-secret',
+      );
+    });
+  });
+
   test('reports unknown outcome when credential persistence fails after clearing verified state', {
     skip:
       process.platform === 'win32'
@@ -3050,6 +3131,383 @@ describe('runtime policy stores', () => {
     });
   });
 
+  test('a stale client cannot recreate a proxy credential after another client disables authentication', async () => {
+    await withInteractiveOwner(async ({ stores }) => {
+      const initialPolicy = await stores.runtimePolicy.getSnapshot();
+      const configured = await stores.operations.updateNetworkProxy({
+        expectedPolicyRevision: initialPolicy.revision,
+        expectedCredential: null,
+        networkProxy: {
+          ...initialPolicy.policy.networkProxy,
+          enabled: true,
+          authEnabled: true,
+          username: 'proxy-user',
+        },
+        credential: { kind: 'replace', secret: 'initial-secret' },
+      });
+      assert.equal(configured.kind, 'committed');
+      if (configured.kind !== 'committed') return;
+      assert.equal(configured.credentialStatus.configured, true);
+      if (!configured.credentialStatus.configured) return;
+
+      // Both clients observed the same Host-owned policy and credential basis.
+      const clientAPolicyRevision = configured.snapshot.revision;
+      const clientACredential = credentialBasis(configured.credentialStatus);
+      const clientBPolicyRevision = configured.snapshot.revision;
+      const clientBCredential = credentialBasis(configured.credentialStatus);
+
+      const disabled = await stores.operations.updateNetworkProxy({
+        expectedPolicyRevision: clientBPolicyRevision,
+        expectedCredential: clientBCredential,
+        networkProxy: {
+          ...configured.snapshot.policy.networkProxy,
+          authEnabled: false,
+          username: '',
+        },
+        credential: { kind: 'delete' },
+      });
+      assert.equal(disabled.kind, 'committed');
+      if (disabled.kind !== 'committed') return;
+
+      const staleReplacement = await stores.operations.updateNetworkProxy({
+        expectedPolicyRevision: clientAPolicyRevision,
+        expectedCredential: clientACredential,
+        networkProxy: configured.snapshot.policy.networkProxy,
+        credential: { kind: 'replace', secret: 'must-not-return' },
+      });
+      assert.ok(
+        staleReplacement.kind === 'revision_conflict' ||
+          staleReplacement.kind === 'credential_stale',
+      );
+
+      const finalPolicy = await stores.runtimePolicy.getSnapshot();
+      const finalCredential = await getCredentialStatus(stores.credentialVault, proxyCredential());
+      assert.equal(finalPolicy.policy.networkProxy.authEnabled, false);
+      assert.equal(finalCredential.configured, false);
+    });
+  });
+
+  test('a bound proxy credential import cannot replace the secret after the proxy target changes', async () => {
+    await withInteractiveOwner(async ({ stores }) => {
+      const initial = await stores.runtimePolicy.getSnapshot();
+      const source = await stores.operations.updateNetworkProxy({
+        expectedPolicyRevision: initial.revision,
+        expectedCredential: null,
+        networkProxy: {
+          ...initial.policy.networkProxy,
+          enabled: true,
+          host: 'proxy-a.example',
+          port: 8080,
+          authEnabled: true,
+          username: 'source-user',
+        },
+        credential: { kind: 'replace', secret: 'existing-secret' },
+      });
+      assert.equal(source.kind, 'committed');
+      if (source.kind !== 'committed' || !source.credentialStatus.configured) return;
+
+      const retargeted = await stores.operations.updateNetworkProxy({
+        expectedPolicyRevision: source.snapshot.revision,
+        expectedCredential: credentialBasis(source.credentialStatus),
+        networkProxy: {
+          ...source.snapshot.policy.networkProxy,
+          host: 'proxy-b.example',
+          username: 'target-user',
+        },
+        credential: { kind: 'keep' },
+      });
+      assert.equal(retargeted.kind, 'committed');
+      if (retargeted.kind !== 'committed') return;
+
+      const outcome = await stores.operations.updateNetworkProxy({
+        expectedPolicyRevision: retargeted.snapshot.revision,
+        expectedCredential: credentialBasis(source.credentialStatus),
+        networkProxy: retargeted.snapshot.policy.networkProxy,
+        credential: {
+          kind: 'replace',
+          secret: 'source-import-secret',
+          expectedTarget: {
+            protocol: 'http',
+            host: 'proxy-a.example',
+            port: 8080,
+            username: 'source-user',
+          },
+        },
+      } as never);
+
+      assert.deepEqual(outcome, {
+        kind: 'proxy_target_mismatch',
+        expected: {
+          protocol: 'http',
+          host: 'proxy-a.example',
+          port: 8080,
+          username: 'source-user',
+        },
+        actual: {
+          protocol: 'http',
+          host: 'proxy-b.example',
+          port: 8080,
+          username: 'target-user',
+        },
+      });
+      const exported = await stores.operations.exportCredentialMaterial(proxyCredential());
+      assert.equal(exported?.secret, 'existing-secret');
+      assert.deepEqual(exported?.proxyTarget, {
+        protocol: 'http',
+        host: 'proxy-b.example',
+        port: 8080,
+        username: 'target-user',
+      });
+    });
+  });
+
+  test('proxy replacement failure before vault publication leaves both stores unchanged', {
+    skip:
+      process.platform === 'win32'
+        ? 'POSIX file handles are required to inject persistence failures'
+        : false,
+  }, async () => {
+    await withInteractiveOwner(async ({ root, stores }) => {
+      const initial = await stores.runtimePolicy.getSnapshot();
+      const probe = await open(root, 'r');
+      const fileHandlePrototype = Object.getPrototypeOf(probe) as {
+        sync: typeof probe.sync;
+      };
+      const originalSync = fileHandlePrototype.sync;
+      await probe.close();
+      let syncCalls = 0;
+      const syncMock = mock.method(
+        fileHandlePrototype,
+        'sync',
+        async function (this: typeof probe) {
+          syncCalls += 1;
+          if (syncCalls === 1) throw new Error('injected proxy credential pre-publication failure');
+          return originalSync.call(this);
+        },
+      );
+
+      try {
+        await assert.rejects(
+          stores.operations.updateNetworkProxy({
+            expectedPolicyRevision: initial.revision,
+            expectedCredential: null,
+            networkProxy: {
+              ...initial.policy.networkProxy,
+              enabled: true,
+              host: 'unchanged.proxy.internal',
+              authEnabled: true,
+              username: 'unchanged-user',
+            },
+            credential: { kind: 'replace', secret: 'must-not-persist' },
+          }),
+          isStoreError('io_failed'),
+        );
+      } finally {
+        syncMock.mock.restore();
+      }
+
+      assert.deepEqual(await stores.runtimePolicy.getSnapshot(), initial);
+      assert.equal(
+        (await getCredentialStatus(stores.credentialVault, proxyCredential())).configured,
+        false,
+      );
+    });
+  });
+
+  test('proxy replacement never persists its secret outside the credential vault', {
+    skip:
+      process.platform === 'win32'
+        ? 'POSIX file handles are required to inject persistence failures'
+        : false,
+  }, async () => {
+    await withInteractiveOwner(async ({ root, stores }) => {
+      const initial = await stores.runtimePolicy.getSnapshot();
+      const secret = 'vault-only-proxy-secret';
+      const probe = await open(root, 'r');
+      const fileHandlePrototype = Object.getPrototypeOf(probe) as {
+        sync: typeof probe.sync;
+      };
+      const originalSync = fileHandlePrototype.sync;
+      await probe.close();
+      let syncCalls = 0;
+      const syncMock = mock.method(
+        fileHandlePrototype,
+        'sync',
+        async function (this: typeof probe) {
+          syncCalls += 1;
+          if (syncCalls === 3) throw new Error('injected proxy policy persistence failure');
+          return originalSync.call(this);
+        },
+      );
+
+      try {
+        await assert.rejects(
+          stores.operations.updateNetworkProxy({
+            expectedPolicyRevision: initial.revision,
+            expectedCredential: null,
+            networkProxy: {
+              ...initial.policy.networkProxy,
+              enabled: true,
+              host: 'vault-only.proxy.internal',
+              port: 7897,
+              authEnabled: true,
+              username: 'vault-only-user',
+            },
+            credential: { kind: 'replace', secret },
+          }),
+          isStoreError('commit_outcome_unknown'),
+        );
+      } finally {
+        syncMock.mock.restore();
+      }
+
+      const filesContainingSecret: string[] = [];
+      for (const entry of await readdir(root)) {
+        if (!entry.endsWith('.json')) continue;
+        if ((await readFile(join(root, entry), 'utf8')).includes(secret)) {
+          filesContainingSecret.push(entry);
+        }
+      }
+      assert.deepEqual(filesContainingSecret, ['credential-vault.json']);
+      assert.equal(existsSync(join(root, 'runtime-policy-network-proxy.json')), false);
+      assert.equal(existsSync(join(root, 'runtime-policy.json')), false);
+    });
+  });
+
+  test('authentication disable failure before policy publication leaves both stores unchanged', {
+    skip:
+      process.platform === 'win32'
+        ? 'POSIX file handles are required to inject persistence failures'
+        : false,
+  }, async () => {
+    await withInteractiveOwner(async ({ root, stores }) => {
+      const initial = await stores.runtimePolicy.getSnapshot();
+      const secret = 'unchanged-disabled-proxy-secret';
+      const configured = await stores.operations.updateNetworkProxy({
+        expectedPolicyRevision: initial.revision,
+        expectedCredential: null,
+        networkProxy: {
+          ...initial.policy.networkProxy,
+          enabled: true,
+          authEnabled: true,
+          username: 'unchanged-disable-user',
+        },
+        credential: { kind: 'replace', secret },
+      });
+      assert.equal(configured.kind, 'committed');
+      if (configured.kind !== 'committed') return;
+
+      const probe = await open(root, 'r');
+      const fileHandlePrototype = Object.getPrototypeOf(probe) as {
+        sync: typeof probe.sync;
+      };
+      const originalSync = fileHandlePrototype.sync;
+      await probe.close();
+      let syncCalls = 0;
+      const syncMock = mock.method(
+        fileHandlePrototype,
+        'sync',
+        async function (this: typeof probe) {
+          syncCalls += 1;
+          if (syncCalls === 1) throw new Error('injected proxy policy pre-publication failure');
+          return originalSync.call(this);
+        },
+      );
+
+      try {
+        await assert.rejects(
+          stores.operations.updateNetworkProxy({
+            expectedPolicyRevision: configured.snapshot.revision,
+            expectedCredential: credentialBasis(configured.credentialStatus),
+            networkProxy: {
+              ...configured.snapshot.policy.networkProxy,
+              authEnabled: false,
+              username: '',
+            },
+            credential: { kind: 'delete' },
+          }),
+          isStoreError('io_failed'),
+        );
+      } finally {
+        syncMock.mock.restore();
+      }
+
+      assert.deepEqual(await stores.runtimePolicy.getSnapshot(), configured.snapshot);
+      assert.equal(
+        (await getCredentialStatus(stores.credentialVault, proxyCredential())).configured,
+        true,
+      );
+    });
+  });
+
+  test('disabling proxy authentication commits policy before deleting its credential', {
+    skip:
+      process.platform === 'win32'
+        ? 'POSIX file handles are required to inject persistence failures'
+        : false,
+  }, async () => {
+    await withInteractiveOwner(async ({ root, stores }) => {
+      const initial = await stores.runtimePolicy.getSnapshot();
+      const secret = 'retained-disabled-proxy-secret';
+      const configured = await stores.operations.updateNetworkProxy({
+        expectedPolicyRevision: initial.revision,
+        expectedCredential: null,
+        networkProxy: {
+          ...initial.policy.networkProxy,
+          enabled: true,
+          host: 'disable-order.proxy.internal',
+          port: 7897,
+          authEnabled: true,
+          username: 'disable-order-user',
+        },
+        credential: { kind: 'replace', secret },
+      });
+      assert.equal(configured.kind, 'committed');
+      if (configured.kind !== 'committed') return;
+
+      const probe = await open(root, 'r');
+      const fileHandlePrototype = Object.getPrototypeOf(probe) as {
+        sync: typeof probe.sync;
+      };
+      const originalSync = fileHandlePrototype.sync;
+      await probe.close();
+      let syncCalls = 0;
+      const syncMock = mock.method(
+        fileHandlePrototype,
+        'sync',
+        async function (this: typeof probe) {
+          syncCalls += 1;
+          if (syncCalls === 3) throw new Error('injected proxy credential deletion failure');
+          return originalSync.call(this);
+        },
+      );
+
+      try {
+        await assert.rejects(
+          stores.operations.updateNetworkProxy({
+            expectedPolicyRevision: configured.snapshot.revision,
+            expectedCredential: credentialBasis(configured.credentialStatus),
+            networkProxy: {
+              ...configured.snapshot.policy.networkProxy,
+              authEnabled: false,
+              username: '',
+            },
+            credential: { kind: 'delete' },
+          }),
+          isStoreError('commit_outcome_unknown'),
+        );
+      } finally {
+        syncMock.mock.restore();
+      }
+
+      const persistedPolicy = JSON.parse(
+        await readFile(join(root, 'runtime-policy.json'), 'utf8'),
+      ) as { readonly policy: { readonly networkProxy: RuntimePolicy['networkProxy'] } };
+      assert.equal(persistedPolicy.policy.networkProxy.authEnabled, false);
+      assert.ok((await readFile(join(root, 'credential-vault.json'), 'utf8')).includes(secret));
+    });
+  });
+
   test('blocks WebFetch while privacy mode is active', async () => {
     await withInteractiveOwner(async ({ stores }) => {
       const policy = await stores.runtimePolicy.mutate({
diff --git a/packages/storage/src/__tests__/settings-store-onboarding.test.ts b/packages/storage/src/__tests__/settings-store-onboarding.test.ts
index 3852f11019..525b41af13 100644
--- a/packages/storage/src/__tests__/settings-store-onboarding.test.ts
+++ b/packages/storage/src/__tests__/settings-store-onboarding.test.ts
@@ -270,6 +270,45 @@ describe('SettingsStore.updateIf', () => {
 });
 
 describe('SettingsStore.get file recovery', () => {
+  it('atomically removes legacy proxy credentials from settings.json on read', async () => {
+    const workspaceRoot = await mkdtemp(join(tmpdir(), 'maka-settings-proxy-migration-'));
+    try {
+      const store = createSettingsStore(workspaceRoot);
+      const settingsPath = join(workspaceRoot, 'settings.json');
+      await writeFile(
+        settingsPath,
+        JSON.stringify({
+          schemaVersion: 1,
+          network: {
+            proxy: {
+              enabled: true,
+              host: '127.0.0.1',
+              port: 7897,
+              password: 'legacy-plaintext-secret',
+              passwordConfigured: true,
+            },
+          },
+        }),
+        'utf8',
+      );
+
+      const settings = await store.get();
+      const migrated = JSON.parse(await readFile(settingsPath, 'utf8')) as {
+        network: { proxy: Record<string, unknown> };
+      };
+
+      assert.equal(settings.network.proxy.host, '127.0.0.1');
+      assert.equal('password' in migrated.network.proxy, false);
+      assert.equal('passwordConfigured' in migrated.network.proxy, false);
+      assert.equal(
+        (await readFile(settingsPath, 'utf8')).includes('legacy-plaintext-secret'),
+        false,
+      );
+    } finally {
+      await rm(workspaceRoot, { recursive: true, force: true });
+    }
+  });
+
   it('serializes concurrent first reads while creating default settings', async () => {
     const workspaceRoot = await mkdtemp(join(tmpdir(), 'maka-settings-concurrent-defaults-'));
     const originalNow = Date.now;
diff --git a/packages/storage/src/runtime-policy-stores.ts b/packages/storage/src/runtime-policy-stores.ts
index cf4b882194..f3c4a97689 100644
--- a/packages/storage/src/runtime-policy-stores.ts
+++ b/packages/storage/src/runtime-policy-stores.ts
@@ -20,6 +20,7 @@
 import type {
   ConnectionCatalogMutationResult,
   ConnectionCatalogSnapshot,
+  ConnectionCredentialTarget,
   CreateCatalogConnectionInput,
   CredentialLocator,
   CredentialMutationResult,
@@ -236,7 +237,16 @@ function createWriterFacade(coordinator: RuntimePolicyCoordinator): RuntimePolic
       delete: (input) => coordinator.deleteCredential(input),
     },
     operations: {
-      exportCredentialMaterial: (locator) => coordinator.exportCredentialMaterial(locator),
+      updateNetworkProxy: (input) => coordinator.updateNetworkProxy(input),
+      exportCredentialMaterial: ((
+        locator: CredentialLocator,
+        expectedConnection?: ConnectionCredentialTarget,
+      ) =>
+        expectedConnection
+          ? coordinator.exportCredentialMaterial(locator, expectedConnection)
+          : coordinator.exportCredentialMaterial(
+              locator,
+            )) as OperationCoordinator['exportCredentialMaterial'],
       getConnectionRequestHeaders: (connectionId) =>
         coordinator.getConnectionRequestHeaders(connectionId),
       replaceConnectionRequestHeaders: (connectionId, updates) =>
diff --git a/packages/storage/src/runtime-policy/coordinator.ts b/packages/storage/src/runtime-policy/coordinator.ts
index 7669f9f7d1..affb34997d 100644
--- a/packages/storage/src/runtime-policy/coordinator.ts
+++ b/packages/storage/src/runtime-policy/coordinator.ts
@@ -18,9 +18,12 @@
  */
 
 import { randomUUID } from 'node:crypto';
+import { isDeepStrictEqual } from 'node:util';
 import {
   CONNECTION_CATALOG_MAX_CONNECTIONS,
   decodeConnectionModelId,
+  connectionCredentialTarget,
+  decodeConnectionCredentialTarget,
   decodeConnectionSlug,
   decodeProviderType,
   decodeRuntimePolicyEntityId,
@@ -35,8 +38,11 @@ import {
   RequestCustomizationValidationError,
   normalizeCredentialSecret,
   normalizeCatalogConnectionBaseUrl,
+  normalizeNetworkProxyUpdate,
+  networkProxyCredentialTarget,
   type ConnectionCatalogEntry,
   type ConnectionCatalogSnapshot,
+  type ConnectionCredentialTarget,
   type ConnectionVersionBasis,
   type ConnectionModelDiscoveryResult,
   type ConnectionTestSummary,
@@ -54,6 +60,8 @@ import {
   type MigrateSystemSeedInput,
   type SetDefaultConnectionTargetInput,
   type UpdateCatalogConnectionInput,
+  type UpdateNetworkProxyInput,
+  type UpdateNetworkProxyResult,
 } from '@maka/core/runtime-policy';
 import {
   applyModelFactOverridesToConnection,
@@ -98,6 +106,7 @@ import {
   commitOutcomeUnknown,
   decodeConnectionInput,
   decodeCredentialInput,
+  decodePolicyInput,
   RuntimePolicyStoreError,
 } from './errors.js';
 import {
@@ -105,6 +114,7 @@ import {
   connectionRequestHeadersLocator,
   type CredentialStatusQueryResult,
   type BeginConnectionTestResult,
+  type BoundCredentialMaterialExportResult,
   type BeginModelFetchResult,
   type BeginInteractiveOAuthLoginResult,
   type CompareAndSetOAuthCredentialInput,
@@ -343,6 +353,67 @@ export class RuntimePolicyCoordinator {
     });
   }
 
+  updateNetworkProxy(rawInput: UpdateNetworkProxyInput): Promise<UpdateNetworkProxyResult> {
+    return this.inLane(async (root) => {
+      const input = decodePolicyInput(() => normalizeNetworkProxyUpdate(rawInput));
+      const policy = await this.policy.read(root);
+      const preparedPolicy = this.policy.prepareMutation(policy, {
+        expectedRevision: input.expectedPolicyRevision,
+        operation: { kind: 'set_network_proxy', value: input.networkProxy },
+      });
+      if (preparedPolicy.kind !== 'ready') return preparedPolicy;
+
+      if (
+        input.credential.kind === 'replace' &&
+        input.credential.expectedTarget &&
+        !isDeepStrictEqual(
+          networkProxyCredentialTarget(policy.policy.networkProxy),
+          input.credential.expectedTarget,
+        )
+      ) {
+        return deepFreeze({
+          kind: 'proxy_target_mismatch' as const,
+          expected: input.credential.expectedTarget,
+          actual: networkProxyCredentialTarget(policy.policy.networkProxy),
+        });
+      }
+
+      const vault = await this.vault.read(root);
+      const existing = findCredential(vault, networkProxyCredentialLocator());
+      if (!matchesCredentialExpectation(existing, input.expectedCredential)) {
+        return deepFreeze({
+          kind: 'credential_stale' as const,
+          expected: input.expectedCredential,
+          actual: existing ? credentialBasis(existing) : null,
+        });
+      }
+      // Preflight every document before publishing either side of the compound update.
+      if (input.credential.kind === 'replace' && existing?.secret !== input.credential.secret) {
+        const prepared = this.vault.prepareSet(vault, {
+          locator: networkProxyCredentialLocator(),
+          expected: existing
+            ? { credentialId: existing.credentialId, revision: existing.revision }
+            : null,
+          secret: input.credential.secret,
+        });
+        if (prepared.kind !== 'ready') {
+          if (prepared.kind === 'credential_stale') return prepared;
+          throw codecError('invalid_credential_input', 'Network proxy credential is invalid');
+        }
+      } else if (input.credential.kind === 'delete' && existing) {
+        const prepared = this.vault.prepareDelete(vault, {
+          expected: credentialBasis(existing),
+        });
+        if (prepared.kind !== 'ready') {
+          if (prepared.kind === 'credential_stale') return prepared;
+          throw codecError('invalid_credential_input', 'Network proxy credential is invalid');
+        }
+      }
+
+      return this.applyNetworkProxyUpdate(root, input);
+    });
+  }
+
   createConnection(input: CreateCatalogConnectionInput) {
     return this.inLane(async (root) =>
       this.projectCatalogMutation(root, await this.catalog.create(root, input)),
@@ -431,6 +502,19 @@ export class RuntimePolicyCoordinator {
         if (!connection) {
           return deepFreeze({ kind: 'connection_not_found' as const });
         }
+        if (
+          input.expectedConnection &&
+          !isDeepStrictEqual(connectionCredentialTarget(connection), input.expectedConnection)
+        ) {
+          return deepFreeze({
+            kind: 'connection_stale' as const,
+            expected: {
+              connectionId: input.expectedConnection.connectionId,
+              revision: input.expectedConnection.revision,
+            },
+            actual: connectionBasis(connection),
+          });
+        }
         assertConnectionIsWritable(connection);
         const required = connectionCredentialLocator(
           connection.connectionId,
@@ -776,15 +860,63 @@ export class RuntimePolicyCoordinator {
 
   exportCredentialMaterial(
     rawLocator: CredentialLocator,
-  ): Promise<RuntimePolicyCredentialMaterial | null> {
+  ): Promise<RuntimePolicyCredentialMaterial | null>;
+  exportCredentialMaterial(
+    rawLocator: CredentialLocator,
+    rawExpectedConnection: ConnectionCredentialTarget,
+  ): Promise<BoundCredentialMaterialExportResult>;
+  exportCredentialMaterial(
+    rawLocator: CredentialLocator,
+    rawExpectedConnection?: ConnectionCredentialTarget,
+  ): Promise<RuntimePolicyCredentialMaterial | null | BoundCredentialMaterialExportResult> {
     return this.inLane(async (root) => {
       const locator = decodeCredentialInput(() => decodeCredentialLocator(rawLocator));
+      const expectedConnection = rawExpectedConnection
+        ? decodeConnectionInput(() => decodeConnectionCredentialTarget(rawExpectedConnection))
+        : undefined;
+      if (expectedConnection && locator.scope !== 'connection') {
+        throw codecError(
+          'invalid_credential_input',
+          'Only connection credentials accept a connection target basis',
+        );
+      }
       if (locator.scope === 'connection') {
         const catalog = await this.catalog.read(root);
-        if (!this.validateConnectionCredentialLocator(catalog, locator)) return null;
+        const connection = findConnection(catalog, locator);
+        if (
+          expectedConnection &&
+          (!connection ||
+            !isDeepStrictEqual(connectionCredentialTarget(connection), expectedConnection))
+        ) {
+          return deepFreeze({
+            kind: 'connection_stale' as const,
+            expected: {
+              connectionId: expectedConnection.connectionId,
+              revision: expectedConnection.revision,
+            },
+            actual: connection ? connectionBasis(connection) : null,
+          });
+        }
+        if (!this.validateConnectionCredentialLocator(catalog, locator)) {
+          return expectedConnection
+            ? deepFreeze({ kind: 'exported' as const, material: null })
+            : null;
+        }
       }
       const credential = findCredential(await this.vault.read(root), locator);
-      return credential ? credentialMaterial(credential) : null;
+      const material = credential
+        ? {
+            ...credentialMaterial(credential),
+            ...(locator.scope === 'network_proxy'
+              ? {
+                  proxyTarget: networkProxyCredentialTarget(
+                    (await this.policy.read(root)).policy.networkProxy,
+                  ),
+                }
+              : {}),
+          }
+        : null;
+      return expectedConnection ? deepFreeze({ kind: 'exported' as const, material }) : material;
     });
   }
 
@@ -1768,6 +1900,95 @@ export class RuntimePolicyCoordinator {
     }
   }
 
+  private async applyNetworkProxyUpdate(
+    root: string,
+    input: UpdateNetworkProxyInput,
+  ): Promise<Extract<UpdateNetworkProxyResult, { readonly kind: 'committed' }>> {
+    const policy = await this.policy.read(root);
+    const vault = await this.vault.read(root);
+    const locator = networkProxyCredentialLocator();
+    const existing = findCredential(vault, locator);
+    const credentialChanged =
+      input.credential.kind === 'replace'
+        ? existing?.secret !== input.credential.secret
+        : input.credential.kind === 'delete' && existing !== undefined;
+    const proxyChanged = !isDeepStrictEqual(policy.policy.networkProxy, input.networkProxy);
+    const effectiveProxyChanged = !sameEffectiveProxyConfiguration(
+      effectiveProxyConfigurationBasis(policy.policy.networkProxy),
+      effectiveProxyConfigurationBasis(input.networkProxy),
+    );
+    const cleared =
+      credentialChanged || effectiveProxyChanged
+        ? await this.catalog.clearAllConnectionLastTests(root, await this.catalog.read(root))
+        : false;
+    let durableChange = cleared;
+    let snapshot = policySnapshot(policy);
+    try {
+      const commitCredential = async (): Promise<void> => {
+        if (input.credential.kind === 'replace' && credentialChanged) {
+          const prepared = this.vault.prepareSet(vault, {
+            locator,
+            expected: existing
+              ? { credentialId: existing.credentialId, revision: existing.revision }
+              : null,
+            secret: input.credential.secret,
+          });
+          if (prepared.kind !== 'ready') {
+            throw codecError('invalid_document', 'Network proxy credential update became stale');
+          }
+          await this.vault.commitSet(root, prepared);
+          durableChange = true;
+        } else if (input.credential.kind === 'delete' && existing) {
+          const prepared = this.vault.prepareDelete(vault, {
+            expected: credentialBasis(existing),
+          });
+          if (prepared.kind !== 'ready') {
+            throw codecError('invalid_document', 'Network proxy credential deletion became stale');
+          }
+          await this.vault.commitDelete(root, prepared);
+          durableChange = true;
+        }
+      };
+
+      const commitPolicy = async (): Promise<void> => {
+        if (!proxyChanged) return;
+        const prepared = this.policy.prepareMutation(policy, {
+          expectedRevision: policy.revision,
+          operation: { kind: 'set_network_proxy', value: input.networkProxy },
+        });
+        if (prepared.kind !== 'ready') {
+          throw codecError('invalid_document', 'Network proxy policy update became stale');
+        }
+        snapshot = (await this.policy.commitMutation(root, prepared)).snapshot;
+        durableChange = true;
+      };
+
+      // Never leave an enabled policy pointing at an absent credential: publish a
+      // replacement before enabling its use, and retire credential use before deletion.
+      if (
+        input.credential.kind === 'delete' &&
+        !requiresNetworkProxyCredential(input.networkProxy)
+      ) {
+        await commitPolicy();
+        await commitCredential();
+      } else {
+        await commitCredential();
+        await commitPolicy();
+      }
+    } catch (error) {
+      if (durableChange && !isCommitOutcomeUnknown(error)) {
+        throw commitOutcomeUnknown('Network proxy update committed only some effects', error);
+      }
+      throw error;
+    }
+    const finalVault = await this.vault.read(root);
+    return deepFreeze({
+      kind: 'committed' as const,
+      snapshot,
+      credentialStatus: credentialStatus(finalVault, locator),
+    });
+  }
+
   private async applyInteractiveOAuthEnrollment(
     root: string,
     intent: InteractiveOAuthEnrollmentIntent,
@@ -2027,6 +2248,13 @@ function hideStaleModelFactsVerification(
   };
 }
 
+function matchesCredentialExpectation(
+  actual: ReturnType<typeof findCredential>,
+  expected: CredentialVersionBasis | null,
+): boolean {
+  return expected === null ? actual === undefined : sameCredentialBasis(actual, expected);
+}
+
 function isCommitOutcomeUnknown(error: unknown): error is RuntimePolicyStoreError {
   return error instanceof RuntimePolicyStoreError && error.code === 'commit_outcome_unknown';
 }
diff --git a/packages/storage/src/runtime-policy/operations.ts b/packages/storage/src/runtime-policy/operations.ts
index b27bf35e09..0a6afc6fb3 100644
--- a/packages/storage/src/runtime-policy/operations.ts
+++ b/packages/storage/src/runtime-policy/operations.ts
@@ -20,6 +20,8 @@
 import type {
   ConnectionCatalogEntry,
   ConnectionCatalogSnapshot,
+  ConnectionCredentialTarget,
+  ConnectionVersionBasis,
   ConnectionModelDiscoveryResult,
   ConnectionOnboardingTarget,
   ConnectionTestSummary,
@@ -29,6 +31,9 @@ import type {
   CredentialStatus,
   CredentialVersionBasis,
   RuntimePolicy,
+  NetworkProxyCredentialTarget,
+  UpdateNetworkProxyInput,
+  UpdateNetworkProxyResult,
   RequestHeaderUpdate,
   SavedRequestHeaders,
 } from '@maka/core/runtime-policy';
@@ -41,8 +46,20 @@ export type ConnectionEffectChangedDomain = 'connection' | 'credential' | 'netwo
 
 export interface RuntimePolicyCredentialMaterial extends CredentialVersionBasis {
   readonly secret: string;
+  readonly proxyTarget?: NetworkProxyCredentialTarget;
 }
 
+export type BoundCredentialMaterialExportResult =
+  | {
+      readonly kind: 'exported';
+      readonly material: RuntimePolicyCredentialMaterial | null;
+    }
+  | {
+      readonly kind: 'connection_stale';
+      readonly expected: ConnectionVersionBasis;
+      readonly actual: ConnectionVersionBasis | null;
+    };
+
 export interface RuntimePolicyOperationSecretMaterial {
   readonly connection?: RuntimePolicyCredentialMaterial;
   readonly requestHeaders?: RuntimePolicyCredentialMaterial;
@@ -351,9 +368,14 @@ export type ReplaceConnectionRequestHeadersResult =
   | { readonly kind: 'connection_not_found' };
 
 export interface RuntimePolicyOperationCoordinator {
+  updateNetworkProxy(input: UpdateNetworkProxyInput): Promise<UpdateNetworkProxyResult>;
   exportCredentialMaterial(
     locator: CredentialLocator,
   ): Promise<RuntimePolicyCredentialMaterial | null>;
+  exportCredentialMaterial(
+    locator: CredentialLocator,
+    expectedConnection: ConnectionCredentialTarget,
+  ): Promise<BoundCredentialMaterialExportResult>;
   getConnectionRequestHeaders(connectionId: string): Promise<SavedRequestHeaders | null>;
   replaceConnectionRequestHeaders(
     connectionId: string,
diff --git a/packages/storage/src/settings-store.ts b/packages/storage/src/settings-store.ts
index 39b0377d1b..8b892e30df 100644
--- a/packages/storage/src/settings-store.ts
+++ b/packages/storage/src/settings-store.ts
@@ -19,7 +19,7 @@
 
 import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
 import { dirname, join } from 'node:path';
-import type { AppSettings, SettingsTestResult, UpdateAppSettingsInput } from '@maka/core/settings';
+import type { AppSettings, UpdateAppSettingsInput } from '@maka/core/settings';
 import type { OnboardingMilestone, OnboardingMilestoneId } from '@maka/core/onboarding';
 import { createDefaultSettings, mergeSettings, normalizeSettings } from '@maka/core/settings';
 import { sanitizeOnboardingMilestones } from '@maka/core/onboarding';
@@ -45,7 +45,6 @@ export interface SettingsStore {
     predicate: (current: AppSettings) => boolean,
     patch: ConditionalSettingsPatch,
   ): Promise<{ applied: boolean; settings: AppSettings }>;
-  testNetworkProxy(): Promise<SettingsTestResult>;
   /**
    * PR110b: upsert a single onboarding milestone. Caller passes the
    * desired terminal status; the store stamps `Date.now()` so the
@@ -76,7 +75,7 @@ class FileSettingsStore implements SettingsStore {
   private readonly settingsPath: string;
   private queue: Promise<void> = Promise.resolve();
 
-  constructor(private readonly workspaceRoot: string) {
+  constructor(workspaceRoot: string) {
     this.settingsPath = join(workspaceRoot, 'settings.json');
   }
 
@@ -92,7 +91,12 @@ class FileSettingsStore implements SettingsStore {
   private async readOrCreate(): Promise<AppSettings> {
     try {
       const text = await readFile(this.settingsPath, 'utf8');
-      return normalizeSettings(JSON.parse(text));
+      const persisted: unknown = JSON.parse(text);
+      const settings = normalizeSettings(persisted);
+      if (hasLegacyProxyCredentialFields(persisted)) {
+        await this.write(settings);
+      }
+      return settings;
     } catch (error) {
       if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
       const settings = createDefaultSettings();
@@ -184,28 +188,6 @@ class FileSettingsStore implements SettingsStore {
     return result;
   }
 
-  async testNetworkProxy(): Promise<SettingsTestResult> {
-    const started = Date.now();
-    const settings = await this.get();
-    const proxy = settings.network.proxy;
-    if (!proxy.enabled) {
-      return { ok: true, message: '代理未启用,当前会直接连接。', latencyMs: Date.now() - started };
-    }
-    if (!proxy.host.trim()) return { ok: false, message: '代理服务器地址不能为空' };
-    if (!Number.isInteger(proxy.port) || proxy.port <= 0 || proxy.port > 65535) {
-      return { ok: false, message: '代理端口必须在 1-65535 之间' };
-    }
-    if (proxy.authEnabled && (!proxy.username.trim() || !proxy.password)) {
-      return { ok: false, message: '启用代理认证后需要用户名和密码' };
-    }
-    return {
-      ok: true,
-      message: `代理配置有效:${proxy.protocol}://${proxy.host}:${proxy.port}`,
-      latencyMs: Date.now() - started,
-      details: { bypassList: proxy.bypassList, autoBypassDomains: proxy.autoBypassDomains },
-    };
-  }
-
   private async write(settings: AppSettings): Promise<void> {
     await mkdir(dirname(this.settingsPath), { recursive: true });
     const tempPath = `${this.settingsPath}.${process.pid}.${Date.now()}.tmp`;
@@ -219,3 +201,17 @@ class FileSettingsStore implements SettingsStore {
     return next;
   }
 }
+
+function hasLegacyProxyCredentialFields(value: unknown): boolean {
+  if (!isRecord(value) || !isRecord(value.network) || !isRecord(value.network.proxy)) {
+    return false;
+  }
+  const proxy = value.network.proxy;
+  return ['password', 'passwordConfigured', 'credential'].some((key) =>
+    Object.prototype.hasOwnProperty.call(proxy, key),
+  );
+}
+
+function isRecord(value: unknown): value is Record<string, unknown> {
+  return typeof value === 'object' && value !== null && !Array.isArray(value);
+}
diff --git a/scripts/qualify-released-cli-state-root.test.mjs b/scripts/qualify-released-cli-state-root.test.mjs
index 8660793431..8f99dc5e3c 100644
--- a/scripts/qualify-released-cli-state-root.test.mjs
+++ b/scripts/qualify-released-cli-state-root.test.mjs
@@ -197,9 +197,10 @@ test('durable state covers the control namespace, not only the State Root', () =
   // State Root, not inside it. A golden copy scoped to the State Root alone
   // restored a workspace whose control records had already moved on, so the
   // transition it proved was never the one a user performs.
-  const locations = durableStateLocations('/qualification-scope');
+  const scope = resolve(tmpdir(), 'qualification-scope');
+  const locations = durableStateLocations(scope);
   assert.ok(locations.length >= 2);
-  assert.ok(locations.some(({ live }) => live === join('/qualification-scope', 'state-root')));
+  assert.ok(locations.some(({ live }) => live === join(scope, 'state-root')));
   assert.ok(
     locations.some(({ live }) => live.endsWith(join('.cache', 'maka', 'runtime-hosts'))),
     'the account-local control namespace must be captured and restored',


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org