Skip to content

Commit 9228610

Browse files
committed
fix: protect global agent config defaults
1 parent 88dc177 commit 9228610

3 files changed

Lines changed: 44 additions & 8 deletions

File tree

docs/gateway/security/index.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -512,9 +512,10 @@ The agent-facing `gateway` runtime tool still refuses to rewrite
512512
`tools.exec.ask` or `tools.exec.security`; legacy `tools.bash.*` aliases are
513513
normalized to the same protected exec paths before the write.
514514
Agent-driven `gateway config.apply` and `gateway config.patch` edits are
515-
fail-closed by default: only a narrow set of prompt, model, and mention-gating
516-
paths are agent-tunable. New sensitive config trees are therefore protected
517-
unless they are deliberately added to the allowlist.
515+
fail-closed by default: only a narrow set of low-risk runtime tuning,
516+
mention-gating, and visible-reply paths are agent-tunable. Global model defaults
517+
and prompt overlays stay operator-controlled. New sensitive config trees are
518+
therefore protected unless they are deliberately added to the allowlist.
518519

519520
For any agent/surface that handles untrusted content, deny these by default:
520521

src/agents/tools/gateway-tool-guard-coverage.test.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ function expectAllowedApply(
5858

5959
describe("gateway config mutation guard coverage", () => {
6060
it("keeps a narrow allowlist of agent-tunable config paths", () => {
61-
expect(ALLOWED_GATEWAY_CONFIG_PATHS_FOR_TEST).toContain("agents.defaults.promptOverlays");
62-
expect(ALLOWED_GATEWAY_CONFIG_PATHS_FOR_TEST).toContain("agents.defaults.model");
61+
expect(ALLOWED_GATEWAY_CONFIG_PATHS_FOR_TEST).not.toContain("agents.defaults.promptOverlays");
62+
expect(ALLOWED_GATEWAY_CONFIG_PATHS_FOR_TEST).not.toContain("agents.defaults.model");
6363
expect(ALLOWED_GATEWAY_CONFIG_PATHS_FOR_TEST).toContain("agents.defaults.subagents.thinking");
6464
expect(ALLOWED_GATEWAY_CONFIG_PATHS_FOR_TEST).toContain("agents.list[].id");
6565
expect(ALLOWED_GATEWAY_CONFIG_PATHS_FOR_TEST).toContain("agents.list[].model");
@@ -72,6 +72,20 @@ describe("gateway config mutation guard coverage", () => {
7272
);
7373
});
7474

75+
it("blocks global prompt overlay edits via config.patch", () => {
76+
expectBlocked(
77+
{ agents: { defaults: { promptOverlays: { gpt5: { personality: "off" } } } } },
78+
{ agents: { defaults: { promptOverlays: { gpt5: { personality: "best" } } } } },
79+
);
80+
});
81+
82+
it("blocks global default model edits via config.patch", () => {
83+
expectBlocked(
84+
{ agents: { defaults: { model: { primary: "openai/gpt-5.4" } } } },
85+
{ agents: { defaults: { model: { primary: "openai/gpt-5.5" } } } },
86+
);
87+
});
88+
7589
it("allows documented subagent thinking default edits via config.patch", () => {
7690
expectAllowed(
7791
{},
@@ -546,6 +560,29 @@ describe("gateway config mutation guard coverage", () => {
546560
);
547561
});
548562

563+
it("blocks config.apply replacing global prompt and model defaults", () => {
564+
expectBlockedApply(
565+
{
566+
agents: {
567+
defaults: {
568+
model: { primary: "openai/gpt-5.4" },
569+
promptOverlays: { gpt5: { personality: "off" } },
570+
reasoningDefault: "low",
571+
},
572+
},
573+
},
574+
{
575+
agents: {
576+
defaults: {
577+
model: { primary: "openai/gpt-5.5" },
578+
promptOverlays: { gpt5: { personality: "best" } },
579+
reasoningDefault: "medium",
580+
},
581+
},
582+
},
583+
);
584+
});
585+
549586
it("blocks config.apply duplicate-id protected rewrites", () => {
550587
expectBlockedApply(
551588
{

src/agents/tools/gateway-tool.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ const CONFIG_SCHEMA_PATH_NOT_FOUND_MESSAGE = "config schema path not found";
4040
// trust-boundary control on `config.apply`/`config.patch`, so the runtime tool
4141
// must fail closed and allow only a narrow set of agent-tunable paths.
4242
const ALLOWED_GATEWAY_CONFIG_PATHS = [
43-
// Agent prompt/model tuning.
44-
"agents.defaults.promptOverlays",
45-
"agents.defaults.model",
43+
// Low-risk agent runtime tuning.
4644
"agents.defaults.thinkingDefault",
4745
"agents.defaults.subagents.thinking",
4846
"agents.defaults.reasoningDefault",

0 commit comments

Comments
 (0)