Skip to content

fix(security): enforce disableExternalLLM in team worker contracts#2022

Merged
Yeachan-Heo merged 5 commits intoYeachan-Heo:devfrom
blue-int:security/disable-external-llm
Mar 30, 2026
Merged

fix(security): enforce disableExternalLLM in team worker contracts#2022
Yeachan-Heo merged 5 commits intoYeachan-Heo:devfrom
blue-int:security/disable-external-llm

Conversation

@blue-int
Copy link
Copy Markdown
Contributor

Summary

Enforce disableExternalLLM security setting at runtime. When OMC_SECURITY=strict or disableExternalLLM: true in config, getContract() throws for codex/gemini agent types, preventing external LLM workers from being spawned in team mode.

Claude workers are always allowed regardless of this setting.

Depends on

Changes

  • src/team/model-contract.ts: Guard in getContract() that checks isExternalLLMDisabled() for non-claude agents
  • src/team/__tests__/model-contract.test.ts: 3 new tests (codex blocked, gemini blocked, claude allowed)

Test plan

  • OMC_SECURITY=strictgetContract('codex') throws "disabled by security policy"
  • OMC_SECURITY=strictgetContract('gemini') throws "disabled by security policy"
  • OMC_SECURITY=strictgetContract('claude') succeeds
  • 46/46 model-contract tests pass

🤖 Generated with Claude Code

blue-int and others added 4 commits March 30, 2026 12:43
Add disableRemoteMcp, disableExternalLLM settings.
In strict mode, config files can only tighten security, not relax it.
Wire isAutoUpdateDisabled() into actual auto-update gate.

Constraint: Strict mode must be monotonically secure — file overrides cannot weaken it
Rejected: Allow file override to disable strict flags | defeats the purpose of OMC_SECURITY=strict
Confidence: high
Scope-risk: narrow

Co-Authored-By: Claude <noreply@anthropic.com>
DEFAULTS.disableAutoUpdate was true, causing isSilentAutoUpdateEnabled()
to always return false even without strict mode. Only strict mode should
force-disable auto-update; default behavior is controlled by OMCConfig.

Co-Authored-By: Claude <noreply@anthropic.com>
Address review feedback:
- Mock config file with false overrides in strict mode to verify they're rejected
- Test that strict mode can tighten hardMaxIterations below base (50 < 200)
- Test non-strict mode file overrides work normally
- Test isSilentAutoUpdateEnabled() returns false when OMC_SECURITY=strict
  even with silentAutoUpdate=true in OMCConfig

Co-Authored-By: Claude <noreply@anthropic.com>
Block codex/gemini worker creation when isExternalLLMDisabled() returns
true. getContract() now throws for non-claude agent types when external
LLM is disabled by security policy (OMC_SECURITY=strict or config).

Claude workers are always allowed regardless of this setting.

Co-Authored-By: Claude <noreply@anthropic.com>
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@Yeachan-Heo
Copy link
Copy Markdown
Owner

Reviewed via OMX session. REQUEST_CHANGES.

Blocking issues:

1. Logic-order bug in getContract() (src/team/model-contract.ts:223)
The external-LLM check now runs before validating that agentType is a known agent. In strict mode, getContract('unknown' as any) will throw the external-LLM policy error instead of the existing Unknown agent type... error. This changes behavior for invalid inputs and hides the real problem.

Fix: Move the disableExternalLLM enforcement after the agent-type validation guard.

2. Misleading error message
The thrown error says:

Set OMC_SECURITY to a non-strict value or configure security.disableExternalLLM=false to allow.

But in this PR's own security model, strict mode prevents config-file relaxation. The remediation suggestion contradicts the security policy.

What passed review:

  • Enforcement is correctly scoped for known agents (codex/gemini blocked, claude allowed in strict)
  • Mocked-fs security-config tests are solid (existsSync/readFileSync simulation, strict override protection, cache reset)
  • silentAutoUpdate interaction test is sensible

Please fix the two blocking items and force-push.


[repo owner's gaebal-gajae (clawdbot) 🦞]

Address review feedback:
- Move disableExternalLLM guard after CONTRACTS[agentType] validation
  so unknown agent types still get the correct error
- Remove misleading remediation suggestion that contradicts strict mode
  override protection

Co-Authored-By: Claude <noreply@anthropic.com>
@blue-int
Copy link
Copy Markdown
Contributor Author

Fixed both blocking issues in 0a09dc5d:

  1. Logic order: Moved disableExternalLLM guard after CONTRACTS[agentType] validation. Unknown agent types now correctly throw "Unknown agent type" first.

  2. Error message: Removed misleading remediation suggestion. Now says:

    External LLM provider "codex" is blocked by security policy (disableExternalLLM). Only Claude workers are allowed in the current security configuration.

46/46 tests pass.

Copy link
Copy Markdown
Owner

@Yeachan-Heo Yeachan-Heo left a comment

Choose a reason for hiding this comment

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

Solid work — this PR addresses all the concerns from the #2016 review:

disableExternalLLM enforcement in getContract() — correct guard logic
✅ fs-mocked strict override tests — properly simulates config file override attempts
silentAutoUpdate + security config interaction test — covers the gap
✅ Claude allowed even when external LLM disabled — correct

Minor nit (non-blocking)

The error message in getContract() suggests security.disableExternalLLM=false as an escape hatch, but in strict mode this config override is explicitly ignored by the || protection. Consider adjusting to: "Remove OMC_SECURITY=strict or use a non-strict security mode to allow external LLM providers." — but this is non-blocking.

Since this PR is a superset of #2016, we should close #2016 once this merges.


[repo owner's gaebal-gajae (clawdbot) 🦞]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants