# Unvalidated bundle callable import

Uploaded bundles or plugins resolving dotted paths or MCP servers to server-side execution without an allowlist

_Area: AI and LLM app security. Seen in 2 disclosed reports; latest 2026-09-02. Updated 2026-10-24._

## How it works
A bundle, plugin, or agent definition is treated as data, but some field in it names code the server will import and run. The validator hardens one such field (env expansion, policy handlers) and misses a sibling field (`tools.<name>.callable`, stdio MCP server commands). The runner later resolves the dotted path with `importlib.import_module` + `getattr` and invokes it, or launches the MCP server as a subprocess. The broken assumption: that a bundle is inert configuration. Any field that resolves to a server-side import or process launch is executable code, and the upload route is the trust boundary.

## Where it shows up
- Bundle/plugin fields holding dotted paths (`module.attr`) or command lines, resolved server-side.
- Validators that disable env expansion or enforce a handler allowlist but skip analogous fields.
- Upload routes that check only a coarse permission (edit) and omit ownership guards like `agent.session_id is None`.
- Shared/template objects marked read-only on one endpoint but mutable via a sibling full-bundle route.
- MCP server definitions (stdio) accepted from tenant uploads and launched on runner hosts.

## How to review
Enumerate every spec field that resolves to an import, attribute lookup, or process launch. The invariant: no tenant-supplied bundle may name code outside an explicit allowlist, and shared/template objects must be immutable through every route that mutates them. Check that the full-bundle upload enforces the same guards as field-level edits, and that route authorization is exact-match, not prefix-based, for admin paths [E1](https://bugbountylibrary.com/r/blog%3Aresearch-checkpoint-com-2026-when-llm-gateways-go-wrong-findings-from-litellm.md).

## Variants seen
- Dotted-path tool callable (`subprocess.check_output`) imported and invoked by the runner [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-756x-9hf6-q4h4.md).
- Stdio MCP server injected via bundle overwrite, launched as a subprocess [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-jrrm-9hc7-2v3h.md).
- Config update injecting env vars and S3-loaded Python modules, reached via prefix-matched admin route [E1](https://bugbountylibrary.com/r/blog%3Aresearch-checkpoint-com-2026-when-llm-gateways-go-wrong-findings-from-litellm.md).

## Why fixes fail
Guards added to one endpoint (direct MCP edit) were absent on the parallel full-bundle upload [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-jrrm-9hc7-2v3h.md); hardening one validator field left the sibling callable field open [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-756x-9hf6-q4h4.md).

## Impact and severity
Authenticated runner RCE [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-jrrm-9hc7-2v3h.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-756x-9hf6-q4h4.md); admin takeover and RCE via config injection [E1](https://bugbountylibrary.com/r/blog%3Aresearch-checkpoint-com-2026-when-llm-gateways-go-wrong-findings-from-litellm.md). Severity rises when any authenticated user reaches the route and when shared bundles amplify reach.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Aresearch-checkpoint-com-2026-when-llm-gateways-go-wrong-findings-from-litellm.md
- E2: https://bugbountylibrary.com/r/ghsa%3AGHSA-jrrm-9hc7-2v3h.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-756x-9hf6-q4h4.md
