AutoGen Code Executor Analysis Report
Completed August 12, 2026 · 31 artifacts examined
15Findings
3Critical
8High
4Medium
RAISE maturity 1.40 / 5.0
Executive Summary
Agent Remit (as declared)
The component of an AutoGen multi-agent workflow that takes code blocks produced by other agents, runs them inside an isolation boundary under human oversight, and returns the exit code and captured output. It is authorized to execute code in a Docker container or an Azure Container Apps dynamic session, to upload and download files to that environment, to restart sessions, and to manage container and session lifecycle; the local host executor is a restricted tool requiring explicit operator authorization. Its counterparties are the agent runtime message bus, the operator-configured Docker daemon, and the configured ACA pool endpoint. Human confirmation is required before every code-block execution with no risk-threshold carve-out, and if the sandbox backend is unavailable the executor must halt and alert rather than fall back to unsandboxed host execution.
Behavior Summary (as observed)
The isolation boundary this component exists to provide is real in the Docker and Azure backends but is neither mandatory nor fail-closed: create_default_code_executor downgrades from container to host execution on any Docker failure with only a Python warning, the local executor's docstring advertises a dangerous-command sanitizer that exists nowhere in the tree, and the docker_jupyter server publishes a stateful arbitrary-code kernel gateway on every host interface. Around that core sits a consistent pattern of safe primitives left unwired — a workspace containment check that the Docker backend bypasses for its own generated filenames, a language allowlist enforced in four backends but not the fifth, and an approval gate that exists only in the calling agent and defaults to off. Nothing in any backend records what was executed, so every one of these gaps is also invisible after the fact.
Scope of Analysis
A Python library, not a deployed service: five executor implementations under autogen_ext/code_executors/ (local, docker, docker_jupyter, jupyter, azure) behind the abstract CodeExecutor contract in autogen_core/code_executor/_base.py. Each writes a code block to a file in a working directory and runs it — asyncio.create_subprocess_exec on the host for the local backend, container.exec_run for the Docker backend, an nbclient kernel for the Jupyter backend, a websocket to a containerized Jupyter kernel gateway for docker_jupyter, and an HTTPS POST to the ACA dynamic-sessions endpoint for azure. External surface spans the Docker daemon, a container registry, a published kernel-gateway port, and the ACA pool endpoint. The abstract contract carries no approval hook: execute_code_blocks runs whatever it is handed, and the create_default_code_executor factory in code_executors/__init__.py silently substitutes host execution when Docker is unavailable.
Remit Coverage

Every actionable rule in the Worker Remit, checked against the running code. Gap = declared but unenforced; Partial = enforced but incomplete or bypassable; Vague Policy = too imprecise to verify.

Verified: 8 Gap: 10 Partial: 6 Vague Policy: 0 Enforcement Not Possible: 4 Total Rules: 28
Rule ID Section Rule (quoted) Status Finding
R-01 Prohibited Behaviors "The executor runs only code blocks delivered through the authorized agent workflow, and MUST NOT act on execution instructions arriving outside that delivery path." Enforcement Not Possible
R-02 Prohibited Behaviors "The executor MUST NOT autonomously perform irreversible real-world actions on the basis of generated output (for example publishing or posting content, or sending external communications) — a human decides how execution outputs are used." Verified
R-03 Prohibited Behaviors "The executor MUST NOT expand or redefine its own role beyond executing supplied code blocks and returning their results; it does not set its own goals or acquire capabilities on its own initiative." Verified
R-04 Prohibited Behaviors "The executor MUST NOT be operated as an unattended, production-facing service without the additional safety evaluation, hardening, and human oversight its deployment requires." Enforcement Not Possible
R-05 Approved Communication Channels "Approved Communication Channels" Partial PRAX-2026-08-12-003
R-06 Approved Communication Channels "Only from agents within the same authorized AutoGen runtime" Enforcement Not Possible
R-07 Authorized Counterparties — Trusted People / Accounts "Trusted People / Accounts" Enforcement Not Possible
R-08 Authorized Counterparties — Trusted Services / Integrations "Trusted Services / Integrations" Partial PRAX-2026-08-12-014
R-09 Authorized Counterparties — Trusted Services / Integrations "Only the operator-configured ACA pool-management endpoint / credential provider and the approved Docker daemon target are authorized backend endpoints; any other backend endpoint, daemon target, or credential/token provider is a trust-expansion finding." Partial PRAX-2026-08-12-013
R-10 Authorized Counterparties — Explicitly Forbidden "Arbitrary external network endpoints, third-party services, or MCP servers that are not required to execute the supplied code within the authorized backend." Verified
R-11 Tools and Capabilities — Allowed Tools (Known Good Baseline) "Allowed Tools (Known Good Baseline)" Gap PRAX-2026-08-12-005
R-12 Tools and Capabilities — Restricted Tools (Require Approval Before Use) "A sandboxed execution backend (Docker or Azure Container Apps dynamic sessions) is required for all code execution." Gap PRAX-2026-08-12-001
R-13 Tools and Capabilities — Restricted Tools (Require Approval Before Use) "The local host executor (running code directly on the machine hosting the application) MUST NOT be used unless the operator has explicitly authorized it, and then only in a trusted, non-production context." Partial PRAX-2026-08-12-001
R-14 Tools and Capabilities — Forbidden Tools "The executor MUST NOT carry any capability that grants inbound network access to, or a persistent interactive shell into, the execution environment from outside the authorized runtime." Gap PRAX-2026-08-12-003
R-15 Data Boundaries — Allowed Data Sources "Allowed Data Sources" Verified
R-16 Data Boundaries — Forbidden Data Movement "The executor MUST NOT transmit the contents of the working directory or uploaded files to any destination outside the configured execution environment." Verified
R-17 Data Boundaries — Forbidden Data Movement "Credentials and tokens used to authenticate to a backend MUST NOT be written into generated code files, into execution output, or into logs." Verified
R-18 Data Boundaries — Forbidden Data Movement "Code executed in the sandbox MAY initiate outbound network connections only to operator-configured outbound destinations; any other outbound network destination is a trust-expansion finding." Gap PRAX-2026-08-12-006
R-19 Action Boundaries — Allowed Without Approval "Allowed Without Approval" Partial PRAX-2026-08-12-004
R-20 Action Boundaries — Requires Human Approval Before Execution "Human confirmation by the overseer is required before every code-block execution; there is no risk-threshold carve-out (no category of block is exempt), and a denied confirmation blocks execution." Partial PRAX-2026-08-12-004
R-21 Action Boundaries — Requires Human Approval Before Execution "Installing packages into the host interpreter, or otherwise modifying state outside the working directory and outside the configured sandbox boundary, MUST require human confirmation." Gap PRAX-2026-08-12-010
R-22 Action Boundaries — Never Allowed "The executor MUST NOT execute a code block that the human overseer has denied." Verified
R-23 Action Boundaries — Never Allowed "The executor MUST NOT execute agent- or LLM-generated code outside an isolation boundary (container or remote sandbox), except via the explicitly operator-approved local executor." Gap PRAX-2026-08-12-005
R-24 Action Boundaries — Never Allowed "The executor MUST NOT expose the code-execution environment, or the Docker daemon socket it relies on, to untrusted or public networks." Gap PRAX-2026-08-12-003
R-25 Escalation Rules — Halt Agent and Alert Operator "If the configured sandbox backend (container or remote session) is unavailable, the executor MUST halt and alert the operator rather than falling back to unsandboxed host execution." Gap PRAX-2026-08-12-001
R-26 Escalation Rules — Halt Agent and Alert Operator "If executed code attempts to reach resources outside the sandbox and working directory (host filesystem, unauthorized network destinations, privilege escalation), the executor MUST halt and alert the operator." Gap PRAX-2026-08-12-006
R-27 Escalation Rules — Alert Operator (Do Not Halt) "Alert the operator when a code block is denied at the human-confirmation gate." Verified
R-28 Escalation Rules — Log Only "Log every executed code block together with its exit code and output." Gap PRAX-2026-08-12-011
Findings Register

Findings, ordered by severity — each linked to its remit rule, evidence, and a recommended action. Tag chips jump to the relevant entry in the RAISE framework, the OWASP LLM Top 10, or the OWASP Agentic Top 10.

LLM06 primary — the finding's main OWASP categoryASI10 secondary — a category it also touches

CRITICAL PRAX-2026-08-12-001 The default executor factory silently downgrades from container isolation to host execution when Docker is unavailable or fails to initialize.
Policy Rule — R-12, R-13, R-25 (Worker Remit):
"A sandboxed execution backend (Docker or Azure Container Apps dynamic sessions) is required for all code execution. / The local host executor (running code directly on the machine hosting the application) MUST NOT be used unless the operator has explicitly authorized it, and then only in a trusted, non-production context. / If the configured sandbox backend (container or remote session) is unavailable, the executor MUST halt and alert the operator rather than falling back to unsandboxed host execution."
python/packages/autogen-ext/src/autogen_ext/code_executors/__init__.py:58 — create_default_code_executor, lines 58-80 — Docker branch wrapped in `except Exception: pass`, then falls through to `warnings.warn(...)` and returns LocalCommandLineCodeExecutor python/packages/autogen-ext/src/autogen_ext/code_executors/__init__.py:25 — _is_docker_available() returns False on ImportError or DockerException, and the caller receives a host executor with no error raised
High confidence
Recommended Action
  • In code_executors/__init__.py, raise instead of returning a host executor when Docker is unavailable, and require an explicit opt-in argument (e.g. allow_host_fallback=True) before LocalCommandLineCodeExecutor can ever be returned by this factory.
  • Remove the bare except Exception: pass at line 64 so a Docker initialization failure surfaces to the caller rather than being converted into a silent change of isolation model.
CRITICAL PRAX-2026-08-12-002 The local executor's documented dangerous-command sanitizer does not exist anywhere in the codebase; host shell blocks run unscreened.
python/packages/autogen-ext/src/autogen_ext/code_executors/local/__init__.py:57 — docstring, lines 57-58 — "Command line code is sanitized using regular expression match against a list of dangerous commands"; a tree-wide grep for sanitiz|DANGEROUS across python/ returns this docstring line and nothing else python/packages/autogen-ext/src/autogen_ext/code_executors/local/__init__.py:397 — _execute_code_dont_check_setup, lines 397-435 — env = os.environ.copy() is passed straight to create_subprocess_exec, with pwsh invoked at line 414 using -ExecutionPolicy Bypass
High confidence
Recommended Action
  • Either implement the screening the docstring promises in _execute_code_dont_check_setup before the file is written, or delete the sentence at local/__init__.py:57-58 so operators do not credit a control that does not exist.
  • Replace os.environ.copy() at line 397 with an explicit minimal environment (PATH plus operator-listed variables) so host credentials in the parent environment are not inherited by executed blocks.
CRITICAL PRAX-2026-08-12-003 DockerJupyterServer publishes a stateful arbitrary-code kernel gateway on every host interface, not loopback.
Policy Rule — R-05, R-14, R-24 (Worker Remit):
"Approved Communication Channels / The executor MUST NOT carry any capability that grants inbound network access to, or a persistent interactive shell into, the execution environment from outside the authorized runtime. / The executor MUST NOT expose the code-execution environment, or the Docker daemon socket it relies on, to untrusted or public networks."
python/packages/autogen-ext/src/autogen_ext/code_executors/docker_jupyter/_jupyter_server.py:363 — client.containers.run(..., publish_all_ports=True, ...) at lines 363-372 publishes the gateway port to all host interfaces; connection_info at line 405 still reports host="127.0.0.1" python/packages/autogen-ext/src/autogen_ext/code_executors/docker_jupyter/_jupyter_server.py:278 — DEFAULT_DOCKERFILE CMD, lines 278-282 — kernelgateway started with --KernelGatewayApp.ip=0.0.0.0 and list_kernels=true
High confidence
Recommended Action
  • Replace publish_all_ports=True at _jupyter_server.py:363 with an explicit loopback port map (ports={f"{expose_port}/tcp": ("127.0.0.1", 0)}) so the gateway is reachable only from the host running the runtime.
  • Bind the gateway to 127.0.0.1 inside the container in DEFAULT_DOCKERFILE unless the operator explicitly opts into a wider bind.
HIGH PRAX-2026-08-12-004 The executor contract has no approval interposition point; every backend runs a supplied block immediately on receipt.
Policy Rule — R-19, R-20 (Worker Remit):
"Allowed Without Approval / Human confirmation by the overseer is required before every code-block execution; there is no risk-threshold carve-out (no category of block is exempt), and a denied confirmation blocks execution."
python/packages/autogen-core/src/autogen_core/code_executor/_base.py:53 — execute_code_blocks abstract signature, lines 53-72 — takes only code_blocks and a cancellation token; no approval callback, policy object or confirmation result in the contract python/packages/autogen-ext/src/autogen_ext/code_executors/docker/_docker_code_executor.py:405 — execute_code_blocks, lines 405-419 — runs _setup_functions then _execute_code_dont_check_setup with no confirmation step (the caller's opt-in approval_func at _code_executor_agent.py:691-715 is the only gate, default None)
High confidence
Recommended Action
  • Add an optional approval callback to the CodeExecutor contract in _base.py and invoke it in each backend before the block is written, so the gate travels with the executor rather than with one particular caller.
  • Until that exists, document at each executor's entry point that confirmation is the caller's responsibility and that approval_func defaults to None.
HIGH PRAX-2026-08-12-005 JupyterCodeExecutor runs LLM-generated code in a host kernel with no isolation, no authorization signal, and no warning.
Policy Rule — R-11, R-23 (Worker Remit):
"Allowed Tools (Known Good Baseline) / The executor MUST NOT execute agent- or LLM-generated code outside an isolation boundary (container or remote sandbox), except via the explicitly operator-approved local executor."
python/packages/autogen-ext/src/autogen_ext/code_executors/jupyter/_jupyter_code_executor.py:139 — __init__, lines 139-160 — no warnings.warn and no authorization argument, in contrast with local/__init__.py:163-169 which warns that code will run on the local machine python/packages/autogen-ext/src/autogen_ext/code_executors/jupyter/_jupyter_code_executor.py:283 — start(), lines 283-295 — NotebookClient(kernel_name=self._kernel_name, allow_errors=True) with async_setup_kernel launches the kernel on the host, no container or remote session involved
High confidence
Recommended Action
  • Emit the same construction-time UserWarning the local executor emits, and require an explicit operator flag before JupyterCodeExecutor can be constructed, matching the treatment of the other host-executing backend.
  • Add this backend to the remit's Restricted Tools list (or remove it) so the tool inventory and the code agree on which executors run on the host.
HIGH PRAX-2026-08-12-006 The execution container is created with default networking, root user, full capabilities and no resource ceilings.
Policy Rule — R-18, R-26 (Worker Remit):
"Code executed in the sandbox MAY initiate outbound network connections only to operator-configured outbound destinations; any other outbound network destination is a trust-expansion finding. / If executed code attempts to reach resources outside the sandbox and working directory (host filesystem, unauthorized network destinations, privilege escalation), the executor MUST halt and alert the operator."
python/packages/autogen-ext/src/autogen_ext/code_executors/docker/_docker_code_executor.py:537 — client.containers.create, lines 537-550 — arguments are image, name, entrypoint, command, tty, detach, auto_remove, volumes, working_dir, extra_hosts, device_requests; no network, user, capability, filesystem or resource restriction python/packages/autogen-ext/src/autogen_ext/code_executors/docker/_docker_code_executor.py:360 — command = ["timeout", str(self._timeout), lang_to_cmd(lang), filename] executed via exec_run with no user parameter, so the block runs as the image's default root user
High confidence
Recommended Action
  • Pass network_mode="none" by default in containers.create and require an explicit operator argument to enable networking, so the remit's operator-configured-destinations rule has an enforcement point.
  • Add user, cap_drop=["ALL"], mem_limit and pids_limit to the same call so a runaway or hostile block cannot exhaust the host or escalate inside the container.
HIGH PRAX-2026-08-12-007 DockerJupyterServer chmods the host bind directory to 0777 and mounts it read-write into the execution container.
python/packages/autogen-ext/src/autogen_ext/code_executors/docker_jupyter/_jupyter_server.py:325 — lines 325-328 — self._bind_dir.mkdir(exist_ok=True) followed by os.chmod(bind_dir, 0o777) with no condition or operator override python/packages/autogen-ext/src/autogen_ext/code_executors/docker_jupyter/_jupyter_server.py:360 — volumes = {str(self._bind_dir): {"bind": str(work_dir), "mode": "rw"}} — the same world-writable directory is mounted read-write as the kernel's working directory
High confidence
Recommended Action
Replace os.chmod(bind_dir, 0o777) with 0o700 (or 0o770 plus a matching container user via the user argument) so the execution directory is not writable by every account on the host.
HIGH PRAX-2026-08-12-008 The Docker backend builds the host file path from the model-supplied language string and writes it before validating that language.
python/packages/autogen-ext/src/autogen_ext/code_executors/docker/_docker_code_executor.py:352 — lines 352-357 — filename = f"tmp_code_{sha256(code.encode()).hexdigest()}.{lang}" then code_path = self.work_dir / filename and fout.write(code), where lang came unvalidated from code_block.language at line 341 python/packages/autogen-ext/src/autogen_ext/code_executors/local/__init__.py:364 — the local executor checks `if lang not in self.SUPPORTED_LANGUAGES` and aborts before any filename is constructed — the check the Docker backend omits
High confidence
Recommended Action
  • Move a SUPPORTED_LANGUAGES membership check to the top of _execute_code_dont_check_setup, before the filename is built, mirroring local/__init__.py:364.
  • Resolve the constructed path and assert containment with is_relative_to(self.work_dir.resolve()) before opening it for write, so the generated-name branch gets the same protection the filename-comment branch already has.
HIGH PRAX-2026-08-12-009 Azure download_files writes to a host path built from filenames supplied by the remote session's own file listing, with no containment check.
python/packages/autogen-ext/src/autogen_ext/code_executors/azure/_azure_container_code_executor.py:363 — lines 363-382 — `if file not in available_files: raise` is the only check, then local_path = self.work_dir / file and open_file(local_path, "wb") writes the response body; no resolve() or is_relative_to() python/packages/autogen-ext/src/autogen_ext/code_executors/azure/_azure_container_code_executor.py:303 — get_file_list, lines 303-308 — file_info_list is populated from value["properties"]["filename"] in the session API response, so available_files is remote-controlled
High confidence
Recommended Action
  • In download_files, reduce each name to its basename and then verify local_path.resolve().is_relative_to(self.work_dir.resolve()) before opening it for write.
  • Apply the same normalization when constructing the download URL at line 367, so a name with separators cannot alter the request path either.
HIGH PRAX-2026-08-12-010 Function setup installs packages into the host interpreter and compiles function source in the host process, with no confirmation on either path.
Policy Rule — R-21 (Worker Remit):
"Installing packages into the host interpreter, or otherwise modifying state outside the working directory and outside the configured sandbox boundary, MUST require human confirmation."
python/packages/autogen-ext/src/autogen_ext/code_executors/local/__init__.py:285 — _setup_functions, lines 285-305 — cmd_args = ["-m", "pip", "install", *required_packages] run with py_executable = sys.executable when self._virtual_env_context is None, so the host interpreter is modified python/packages/autogen-core/src/autogen_core/code_executor/_func_with_reqs.py:114 — FunctionWithRequirementsStr.__init__, lines 114-117 — spec.loader.exec_module(module) runs the supplied function source inside the host process regardless of which executor backend is configured
High confidence
Recommended Action
  • Require an explicit confirmation callback (or refuse and raise) before _setup_functions installs into sys.executable, and reserve the unprompted path for a supplied virtual_env_context.
  • Document at FunctionWithRequirementsStr that function source is compiled and executed in the host process, so operators do not assume the chosen sandbox covers it.
HIGH PRAX-2026-08-12-011 No backend records what it executed — neither the code block, nor its exit code, nor its output is logged anywhere.
Policy Rule — R-28 (Worker Remit):
"Log every executed code block together with its exit code and output."
python/packages/autogen-ext/src/autogen_ext/code_executors/docker/_docker_code_executor.py:340 — _execute_code_dont_check_setup, lines 340-376 — writes the file, runs the command and collects output with no logging call; the only logging in this module covers container lifecycle and cancellation errors python/packages/autogen-ext/src/autogen_ext/code_executors/local/__init__.py:341 — _execute_code_dont_check_setup, lines 341-474 — same pattern; logging.error appears only for a failed temp-file unlink at line 472
High confidence
Recommended Action
  • Emit one structured record per executed block from each backend — timestamp, backend, language, a hash of the code, exit code and output size — at minimum through a named module logger rather than the root logger.
  • Route that logger to a durable sink in the executors' documentation so the record survives the process, and state whether output content is captured or only its digest.
MEDIUM PRAX-2026-08-12-012 Execution output returns to the model raw — no size cap, no provenance label, no control-character neutralization.
python/packages/autogen-ext/src/autogen_ext/code_executors/docker/_docker_code_executor.py:303 — output = result.output.decode("utf-8") returned unmodified and joined at line 376 with no truncation, labeling or escaping python/packages/autogen-ext/src/autogen_ext/code_executors/jupyter/_jupyter_code_executor.py:218 — ANSI escapes are stripped from error tracebacks only; the stream and execute_result branches at lines 215-237 append content verbatim
High confidence
Recommended Action
  • Cap the returned output in each backend at an operator-configurable byte limit and mark truncation explicitly, so a single block cannot flood the model context.
  • Strip or escape terminal control characters on all output branches, not just Jupyter tracebacks, and wrap the returned text in an explicit untrusted-output delimiter for callers assembling model context.
MEDIUM PRAX-2026-08-12-013 The Jupyter kernel websocket URL is hardcoded to ws:// even when the connection is configured for HTTPS.
Policy Rule — R-09 (Worker Remit):
"Only the operator-configured ACA pool-management endpoint / credential provider and the approved Docker daemon target are authorized backend endpoints; any other backend endpoint, daemon target, or credential/token provider is a trust-expansion finding."
python/packages/autogen-ext/src/autogen_ext/code_executors/docker_jupyter/_jupyter_server.py:78 — _get_ws_base_url, lines 78-80 — returns f"ws://{host}{port}" unconditionally, while _get_api_base_url at lines 73-76 selects https when use_https is set python/packages/autogen-ext/src/autogen_ext/code_executors/docker_jupyter/_jupyter_server.py:122 — get_kernel_client, lines 122-126 — websockets.connect(ws_url, additional_headers=self._get_headers()) sends the "Authorization: token ..." header over that plaintext socket
High confidence
Recommended Action
Select the websocket scheme from use_https in _get_ws_base_url (wss:// when set), matching the REST base-URL helper directly above it.
MEDIUM PRAX-2026-08-12-014 Execution environments are resolved by mutable image tag and pulled with no digest pin or signature verification.
Policy Rule — R-08 (Worker Remit):
"Trusted Services / Integrations"
python/packages/autogen-ext/src/autogen_ext/code_executors/docker/_docker_code_executor.py:519 — lines 519-524 — client.images.get(self._image) then client.images.pull(self._image) on ImageNotFound, where self._image defaults to the mutable tag "python:3-slim" set at line 160; no digest or signature check python/packages/autogen-ext/src/autogen_ext/code_executors/docker_jupyter/_jupyter_server.py:267 — DEFAULT_DOCKERFILE line 267 — FROM quay.io/jupyter/docker-stacks-foundation with no tag or digest, built locally at lines 334-341
High confidence
Recommended Action
  • Pin both images by digest (python:3-slim@sha256:... and a digest-pinned base in DEFAULT_DOCKERFILE) and document the refresh process, so the execution environment is reproducible and reviewable.
  • Add the container registry to the remit's trusted-services list, or make the image a required operator-supplied argument so no default registry pull happens implicitly.
MEDIUM PRAX-2026-08-12-015 The Azure backend caches its access token for the life of the executor with no expiry or refresh handling.
python/packages/autogen-ext/src/autogen_ext/code_executors/azure/_azure_container_code_executor.py:152 — lines 152-156 — "# TODO: expiration?" above _ensure_access_token, which returns immediately when self._access_token is truthy and never inspects the token's expires_on python/packages/autogen-ext/src/autogen_ext/code_executors/azure/_azure_container_code_executor.py:502 — restart(), lines 502-506 — self._access_token = None is the only path that clears the cached credential
High confidence
Recommended Action
Store the AccessToken.expires_on value alongside the token in _ensure_access_token and re-request when it is within a refresh margin of expiry.
What's Working Well

Controls and behaviors that are correctly implemented and verified during this scan. These represent areas where the agent's implementation aligns with its stated policy and security best practices.

Workspace containment check on caller-specified filenames

get_file_name_from_content resolves any # filename: comment against the working directory and raises if the result escapes it, so a code block cannot name a write target outside the workspace. It carries a regression test.

python/packages/autogen-ext/src/autogen_ext/code_executors/_common.py:96-111

Per-block timeout and cancellation on every backend

All five executors bound a single block's runtime — asyncio.wait_for locally, a timeout command in the container, an aiohttp client timeout for ACA — and the Docker backend kills the running command in-container when the cancellation token fires.

python/packages/autogen-ext/src/autogen_ext/code_executors/docker/_docker_code_executor.py:360

Random kernel-gateway auth token by default

DockerJupyterServer generates a 32-byte random token with secrets.token_hex when no token is supplied, so the kernel gateway is authenticated by default rather than open.

python/packages/autogen-ext/src/autogen_ext/code_executors/docker_jupyter/_jupyter_server.py:350-353

Backend-selection warnings at construction

The local executor warns at construction that it runs code on the host and recommends the Docker backend, and the default factory warns when Docker is unavailable, so an operator who reads warnings is told which path they are on.

python/packages/autogen-ext/src/autogen_ext/code_executors/local/__init__.py:163-169

Approval gate with blocking denial in the calling agent (context)

Read as context, not scored as the subject's: CodeExecutorAgent offers an approval_func whose denial returns before execute_code_blocks is called, and warns when none is set. It is opt-in and defaults to None.

python/packages/autogen-agentchat/src/autogen_agentchat/agents/_code_executor_agent.py:691-715
Discovered Log Files

Log files found in the agent's workspace during this scan. Reviewing these files provides runtime evidence to complement the static analysis above.

No log files were found on disk and no log-routing configuration exists in the subject — the executors call the root logger for lifecycle and error text only, with no file sink and no record of executed code, so nothing can be inferred as a runtime log location; see PRAX-2026-08-12-011.
OWASP LLM Top 10 (2026) Coverage

Each card represents one category and shows the top 3 findings. All items in the Findings section.

OWASP Agentic Top 10 (2026) Coverage

Each card represents one category and shows the top 3 findings. All items in the Findings section.

ASI01 Agent Goal Hijack
No findings
ASI02 Tool Misuse and Exploitation
No findings
ASI04 Agentic Supply Chain Vulnerabilities
No findings
ASI06 Memory and Context Poisoning
No findings
ASI08 Cascading Failures
No findings
ASI09 Human-Agent Trust Exploitation
No findings
ASI10 Rogue Agents
No findings
RAISE Maturity Posture

Overall maturity assessment across the six categories of the RAISE framework. This is a maturity model, not a school grade: a score of 3 / 5 means Established, not 60 percent. Most production AI agents today score between Ad hoc (1) and Established (3). See the full RAISE framework reference for the complete scale and scoring.

1.40 / 5.0
Weighted Maturity Score · Ad hoc
Ad hoc. The executors carry genuine isolation machinery — containers, a remote sandbox, per-block timeouts, cancellation, and a tested workspace containment check — but it is optional at every level: the sandbox can be silently swapped for the host, the approval gate lives outside the component and ships off, and the container is created with no network, user, capability, or memory restrictions. The supporting practices that would catch this are largely absent: no component inventory, no dependency scanning, no adversarial testing of the execution surface, and no record of what any backend actually ran. What holds the score above absent is that the safe path genuinely works when an operator chooses it deliberately and configures it themselves.
Limit Your Domain
2/ 5
Confidence: High  |  Weight: 15%  |  Weighted: 0.30
Code-level language allowlists are enforced before execution in the local (local/__init__.py:364) and azure (azure/_azure_container_code_executor.py:444) backends, but the docker backend applies no such check before writing the file, and JupyterCodeExecutor adds a host-kernel capability that appears in neither the remit's Allowed Tools nor its Restricted Tools list.
Balance Your Knowledge Base
1/ 5
Confidence: High  |  Weight: 15%  |  Weighted: 0.15
The dominant path back into the model is execution output, and nothing addresses it — stdout and stderr are decoded and concatenated raw with no size cap, no provenance labeling and no control-character neutralization (_docker_code_executor.py:303, local/__init__.py:458-459), with ANSI stripping applied only to Jupyter tracebacks and the azure output suppressor opt-in and defaulted off.
Implement Zero Trust
2/ 5
Confidence: High  |  Weight: 25%  |  Weighted: 0.50
Real controls run on the execution path — a workspace containment check in _common.py:96-111 with a regression test, per-block timeouts and cancellation in all five backends, and actual container and remote-session isolation — but coverage is incomplete in ways that defeat them: no approval interposition in the CodeExecutor contract, a silent container-to-host downgrade, a sanitizer that is documented but absent, and containers created with no network, user, capability or memory limits.
Manage Your Supply Chain
1/ 5
Confidence: High  |  Weight: 15%  |  Weighted: 0.15
A committed python/uv.lock and exact internal pins are real hygiene, but the execution environments themselves are resolved by mutable tag with no digest or signature verification (python:3-slim, quay.io/jupyter/docker-stacks-foundation), and M10 found no SBOM or component inventory of any kind while M11 found no dependency or container scanning — only repo-wide CodeQL static analysis.
Build an AI Red Team
1/ 5
Confidence: High  |  Weight: 15%  |  Weighted: 0.15
M1, M2, M3 and M5 all returned none — no security-named tests, no adversarial corpus, no adversarial tooling in any dependency file, and no dated result reports — and M9 found no finding-to-fix ledger in the tree; the only material that survives the provenance test is the project's own containment regression test (test_commandline_code_executor.py:217) plus the weekly CodeQL scan recorded at M7, which is its own material with no evidence that any finding changed the design.
Monitor Continuously
1/ 5
Confidence: High  |  Weight: 15%  |  Weighted: 0.15
No backend records the code block, exit code or output it ran, so there is no action-level record at all; the logging present is unstructured root-logger lifecycle and error text with no file sink, and M12 found telemetry only as an OpenTelemetry dependency of sibling packages, with no span or event emitted anywhere under code_executors/.

Maturity Scoring Rubric

Every score above is based on this scale. A score is a snapshot of observable posture — not a verdict on the people or team behind the system.

Score Label Meaning
5 Exemplary Best-in-class; automated, continuously tested, reference quality. Rarely achieved in shipping systems.
4 Strong Comprehensive controls, active management, minor gaps. Production-ready.
3 Established Documented controls consistently applied; known gaps accepted. A respectable baseline.
2 Partial Some controls exist but coverage is incomplete; key gaps remain.
1 Ad hoc Informal or inconsistent measures; relies on individual judgment.
0 Absent No evidence this category is addressed at all.
Weighting: the weighted overall above is the sum of each category's score × weight (the per-category weights are shown on each card). Zero Trust carries double weight by design; see the RAISE framework reference for the rationale.