# Omnigent: Uploaded Agent Bundle Allows Authenticated Runner RCE via Python Callable Tools

Authenticated user uploads an agent bundle whose tool points at `subprocess.check_output`, and the Omnigent runner imports and executes it, yielding local command execution.

- Payout: Research
- Severity: high
- Program: Omnigent
- Found by: xttraa
- Disclosed: 2026-09-02
- CVE: CVE-2026-62675
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-756x-9hf6-q4h4
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-756x-9hf6-q4h4
- Tags: area:ai domain:ai domain:web impact:internal-access impact:rce kind:research platform:ghsa sev:high tech:python technique:source-review vuln:access-control vuln:command-injection vuln:rce

**Target:** Agent bundle upload endpoint `POST /v1/sessions` and runner tool dispatcher
**Root cause:** The bundle validator disables env expansion and can enforce a policy-handler allowlist but never rejects `tools.<name>.callable` dotted paths in tenant-uploaded bundles; the runner later resolves them with `importlib.import_module` + `getattr` and invokes them.
**Steps:**
1. Create a session with a multipart `POST /v1/sessions` request carrying a crafted agent bundle (or submit agent YAML via API/CLI).
2. In the bundle's agent spec, define a tool with a `callable:` path pointing at a dangerous server-side function, e.g. `subprocess.check_output`.
3. Bundle passes `validate_agent_bundle` (expand_env=False, optional handler allowlist) since callable entries are not checked.
4. Invoke the tool in the session; `execute_tool` falls back to `_execute_spec_callable_tool`, which imports the module and calls the resolved function via `asyncio.to_thread(resolved, **args)`.
5. Command runs locally on the runner host with runner permissions.
**How found:** Code review of the upload trust boundary: noticed the validator already treats bundles as untrusted (disables env expansion, enforces handler allowlist) but omits the analogous check for `tools.<name>.callable`, then traced the dispatcher fallback into `_resolve_spec_callable`/`_execute_spec_callable_tool` to confirm import-and-call of attacker-chosen dotted paths.
**Exploitation:** Any authenticated user able to create a custom agent bundle submits a spec declaring a callable tool bound to `subprocess.check_output`; on tool invocation the runner imports and executes it in-process, giving command execution with runner privileges and access to runner files, env vars, credentials and internal services.
**Insight:** When a validator hardens one trusted-only feature (policy handlers) but not its sibling (tool callables), enumerate every spec field that resolves to a server-side import or execution primitive and check each against the same allowlist; grep for `importlib.import_module`/`getattr` sinks reachable from user-supplied config.

