Repository navigation
fix(server): disable code-executing plugins by default, add opt-in flag - #337
Open
akushonkamen wants to merge 2 commits into
Open
akushonkamen wants to merge 2 commits into
akushonkamen wants to merge 2 commits into
Conversation
load_plugins() registered every module with a SLUG and a run() unconditionally, so the executecode plugin - which runs Python from user requests and LLM responses in a live Jupyter kernel with no sandboxing - was active in all deployments by default. With no optillm_api_key set, any unauthenticated request could reach full code execution on the host (issue algorithmicsuperintelligence#302). - Add UNSAFE_DEFAULT_DISABLED_PLUGINS and skip such plugins during load_plugins() with a warning that names the exact flag to re-enable - Opt back in via --enable-unsafe-plugins (CLI), OPTILLM_ENABLE_UNSAFE_PLUGINS (env) or server_config; comma-separated slugs, same three-part pattern as --readurls-allow-internal - Reload plugins after parse_args() in main() so the opt-in (and --plugins-dir) apply to the loaded set; the pre-parse load is kept for --approach choices. With the env var set even the first load includes the plugin, so --approach keeps working - README: mark the executecode row as disabled by default and add a code-execution security section mirroring the readurls one - No sandboxing in this change (nsjail/gVisor-style isolation is out of scope); pure stdlib, no new dependencies Note: this is an intentional default behavior change - deployments that rely on executecode must now set the flag or env var. Fixes algorithmicsuperintelligence#302
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #302
Root cause
load_plugins()inoptillm/server.pyregisters every module that exposes aSLUGand arun()unconditionally, so theexecutecodeplugin is active in all deployments by default. That plugin executes Python blocks taken straight from user requests (and LLM responses) in a live JupyterExecutePreprocessorkernel with no sandboxing: withoptillm_api_keyunset (the default), any unauthenticated request reachingexecutecode-<model>gets arbitrary code execution on the host; with a key, any authorized client has the same power (env vars,~/.ssh, cloud IMDS, lateral movement).This applies the same "secure by default + explicit opt-out" pattern just merged in #334 for
--readurls-allow-internalto the one plugin that unconditionally executes caller-supplied code. The change is exactly the short-term remediation proposed in #302 by the reporter: disable the executecode plugin by default; require explicit opt-in, documented as intended only for air-gapped single-user environments.Change (3 files, +142/-1)
optillm/server.pyUNSAFE_DEFAULT_DISABLED_PLUGINS = {"executecode"}(a set, so future code-executing plugins can be added).load_plugins()skips such plugins unless explicitly enabled, with a warning naming the exact flag:Plugin 'executecode' is disabled by default because it executes arbitrary code. Start optillm with --enable-unsafe-plugins=executecode (env: OPTILLM_ENABLE_UNSAFE_PLUGINS) to allow it.--enable-unsafe-plugins/OPTILLM_ENABLE_UNSAFE_PLUGINS/server_config['enable_unsafe_plugins']option (comma-separated slugs) — the same three-part CLI/env/server_config template as--readurls-allow-internal.main()reloads plugins afterparse_args()populatesserver_config, so the opt-in (and--plugins-dir) applies to the loaded set; the existing pre-parse load stays because--approachchoices are built from the registry. With the env var set, even that first load includes the plugin, so--approach executecode...keeps validating. Disabled plugins also disappear from request dispatch (executecode-<model>slugs) since that reads the same registry.tests/test_plugin_gating.py(new, fully offline): default-off, opt-in via server_config / env / comma list, warning text, plus pure-function tests forextract_python_code()andshould_execute_request_code().README.md: executecode row marked disabled by default, plus a "Code Execution Security" section mirroring the readurls one, carrying the issue's warning that this is only for single-user, air-gapped environments.Default behavior change (intentional)
Deployments relying on
executecodemust start optillm with--enable-unsafe-plugins=executecode(orOPTILLM_ENABLE_UNSAFE_PLUGINS=executecode). This break is the point of the fix; #334 set the precedent that optillm blocks dangerous defaults by default.Red → green evidence
optillm/server.pyfix stashed):pytest tests/test_plugin_gating.py→ImportError: cannot import name 'UNSAFE_DEFAULT_DISABLED_PLUGINS' from 'optillm.server'load_plugins(); 'executecode' in plugin_approaches→True(vulnerable default)pytest tests/test_plugin_gating.py -v→ 11 passed; CI subsetpytest tests/test_plugins.py tests/test_proxy_plugin.py tests/test_approaches.py→ 37 passed;OPTILLM_API_KEY=optillm python tests/test_ci_quick.py→ all checks pass;compileallclean.Scope / follow-ups
cocexecuting LLM-generated code) are untouched; they can be added toUNSAFE_DEFAULT_DISABLED_PLUGINSin a follow-up.@CrepuscularIRIS this implements the short-term mitigation you proposed in #302. @codelion marking as security hardening — happy to adjust the flag name/set membership.
AI disclosure: implementation and tests were prepared with AI assistance, reviewed and submitted by @akushonkamen.