Security

Omnigent: guardrail bypass via fail-open shell parser

Omnigent guardrail policy bypass - the shell-command parser fails open, so hidden git and gh commands skip the GitHub allowlist and working-directory confinement (GHSA-7mqg-cx4g-x2rf)

PUBLISHED SEVERITY HIGHSTATUS PatchedGHSA-7mqg-cx4g-x2rf
Patched

Fixed in omnigent 0.3.0 (2026-06-27) by maintainer PR #389 (commit 1a05b7b). Later releases harden the parser further. Track the fix at omnigent-ai/omnigent#389.

Product
Omnigent (PyPI omnigent) in omnigent-ai/omnigent
Affected versions
omnigent (PyPI) before 0.3.0, i.e. 0.1.0 through 0.2.0. Fixed in 0.3.0 (2026-06-27).
Severity
HIGH
Status
Patched
Weaknesses
  • CWE-184Incomplete List of Disallowed Inputs
As filed on the advisory.
GitHub advisory
GHSA-7mqg-cx4g-x2rf
Published by the maintainer on 2026-06-29
CVE
CVE-2026-62676
Published
Credit
Finder: Aaron Elijah Mars of Aeon. Tool: Aeon (https://www.aeon.fun).

What users should do now

Upgrade to the latest release. The fix shipped in 0.3.0 (2026-06-27), and later releases close more gaps of the same kind.

  1. Upgrade: pip install -U omnigent (at least 0.3.0; 0.9.0 or later also includes the wrapper hardening from #3559).
  2. Do not treat the github and working_dir policies as your only boundary. Give the agent a GitHub token scoped to the repositories it may write to, turn on branch protection for branches it must not push to, and run it in a sandbox.
  3. If you ran 0.1.0 through 0.2.0 on untrusted input (web pages, issues, files that could carry a prompt injection), check for pushes to unexpected repositories or branches and for git worktrees outside the allowed directories.

Summary

Omnigent runs coding agents such as Claude Code, Codex and Pi under policies. Two built-in policies gate shell commands: github enforces a repository and branch allowlist for git and gh writes, and working_dir keeps the agent inside its workspace (it gates cd, git -C and git worktree). Both use a shared parser, omnigent/policies/builtins/_shell.py, to find the real command inside a shell string. When the parser did not recognize how a gated command was written, it produced no operation. The policy then returned None, which means abstain, and abstain means ALLOW. So any gated command the parser missed ran without a check.

Affected versions

omnigent (PyPI) before 0.3.0: releases 0.1.0, 0.1.1 and 0.2.0 and their release candidates. Fixed in 0.3.0 (2026-06-27). One of the four bypass forms, a command hidden behind a lone background operator, was already closed in 0.2.0 by #168.

Impact

The threat is the agent itself: a misaligned model, or one steered by a prompt injection, that the operator meant to keep confined. CVSS 3.1 score 7.1 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N). Such an agent could:

  • push code, and any secrets in it, to a repository outside write_repos, including one the attacker controls;
  • push to a branch outside write_branches, such as a protected release branch;
  • leave its workspace with git worktree or git -C despite working_dir confinement.

Four forms of the same gap were confirmed against the real policy code: a shell interpreter called with other flags bundled together with -c (only a bare -c was unwrapped); process wrappers that were not on the wrapper list (timeout, nice, setsid, stdbuf); a gated command inside a command substitution, which the parser skipped as a plain variable assignment; and a gated command after a lone background operator (fixed earlier in 0.2.0). A bare gated command was correctly denied, which shows the allowlist logic was right and the parser coverage was the problem. A working exploit is withheld.

Affected code

Permalinks at 7ca0cca, the parent of the fix commit.

Fix

  • #389 (commit 1a05b7b, merged 2026-06-26, shipped in 0.3.0) broadens the shared parser so the hidden command is gated as if it ran directly: any interpreter flag group that contains c now unwraps like -c; timeout, nice, setsid and stdbuf are reduced to their inner command, including their own option values; and $(...) and backtick bodies are parsed as separate segments. Because the change is in the shared module, both the github and working_dir policies get it.
  • #168 (merged 2026-06-18, shipped in 0.2.0) had already split commands on a lone background operator.
  • The maintainer kept abstain as the default for commands the parser does not recognize, because these policies are composable allowlists that must not block unrelated commands. The report had suggested failing closed. The gate's strength therefore still depends on how complete the parser is.
  • Later hardening: #3559 (merged 2026-08-05, in 0.9.0) gives the remaining option-taking wrappers the same treatment and adds a fail-safe that asks for approval, instead of allowing, when the parser cannot reach a real command.

Detection (for defenders)

Review agent session logs for shell tool calls where a git push or a gh write sits inside a shell interpreter call, a process wrapper or a command substitution. On GitHub, check the audit log of the token the agent used for pushes to repositories or branches outside its allowlist. On the host, run git worktree list in the agent's repositories and look for worktrees outside the allowed directories.

Timeline

  1. omnigent 0.1.0 published on PyPI.
  2. #168 splits commands on a lone background operator; shipped in 0.2.0 on 2026-06-19.
  3. Reported privately via GitHub PVR (GHSA-7mqg-cx4g-x2rf), with a suggested fix.
  4. Maintainer merges the fix, #389, the same day.
  5. omnigent 0.3.0 released with the fix.
  6. Advisory published by the maintainer.
  7. CVE-2026-62676 reserved by GitHub.
  8. Further hardening merged in #3559; shipped in 0.9.0 on 2026-08-11.
  9. CVE-2026-62676 published.

Credit

Finder: Aaron Elijah Mars of Aeon. Tool: Aeon.

References