`Allowlist` config ? `tried to run {command}, but this environment’s command allowlist blocked it`

Resolved 💬 1 comment Opened Sep 17, 2025 by iyerusad Closed Jan 14, 2026

What is the type of issue?

Documentation is missing

What is the issue?

What: I am unable to find documentation around a whitelist of commands or an allowlist or anything similar.

Want: I am trying to enable an additional command as allowed. In my test case, msbuild.

Model Output Message: "I tried to run msbuild, but this environment’s command allowlist blocked it. I verified the solution compiles offline (packages are checked in), so you can run it locally."

Sample run ouput:
<img width="1273" height="725" alt="Image" src="https://github.com/user-attachments/assets/6b322ecc-376b-4c8c-a4e3-f31c6f493724" />

--

More info:
<Details>

Here is my base command:

codex --ask-for-approval never --sandbox workspace-write -c model_reasoning_effort="high" -c model_reasoning_summary="detailed" -c model_verbosity="high" -c tools.web_search="true" --search

Here is one variant I am trying tried

codex --ask-for-approval never --sandbox workspace-write -c model_reasoning_effort="high" -c model_reasoning_summary="detailed" -c model_verbosity="high" -c tools.web_search="true" -c tools.shell.allowlist='["^(pwsh|powershell)(\\b|$)","^rg(\\b|$)","^sort(\\b|$)","sed","grep","ls","jq","less","msbuild","dotnet","cmd","^npm test($| )", "^pytest($| )","^git (status|diff|log)"]' --search

Here is the prompt:

For tool calling you are running inside a Windows machine with access to pwsh and cmd shells and I have made msbuild, sed, grep, rg, ls, jq, less, curl, and wget commands available. Please compile the project by running msbuild.

--
Background: I am successfully getting strong results running codex-cli within a Window environment natively (no wsl).

Here is my findings:

  1. Command used:

> codex --ask-for-approval never --sandbox workspace-write -c model_reasoning_effort="high" -c model_reasoning_summary="detailed" -c model_verbosity="high" -c tools.web_search="true" --search

  1. Prompting appears to be key, prepending below works a charm:

> For tool calling you are running inside a Windows machine with access to pwsh and cmd shells and I have made msbuild, sed, grep, rg, ls, jq, less, curl, and wget commands available. {rest of my prompt/request}

  1. Providing Unix commands/binaries within powershell gets it to do most/all of the core tasks - find, search, read, patch.
  • Removing and then shimming out specific windows powershell bastardizations, e.g. ls in powershell is key. E.g.:

Powershell profile:
> if (Test-Path Alias:\ls) {
> Remove-Item Alias:ls # Remove built-in ls alias, we replace it with a shim (ls.cmd) that automatically routes to correct command
> }
>
> if (Check-Command cmd) {
> if (Test-Path Alias:\dir) {
> Remove-Item Alias:dir # Remove built-in dir alias, use cmd dir function
> }
> Function dir { cmd /r dir $args }
> }
> if (betterWhereIs curl | Where-Object {$_.Type -eq "Executable"}) {
> if (Test-Path Alias:\curl) {
> Remove-Item Alias:curl # Remove built-in curl alias, prefer curl binary if available
> }
> }

  1. About once out of every ~10 runs the model tries approach of using separate pwsh commands (which wants approval on every single one). Closing and starting the session over usually solves this for me,.
  1. I have not seemingly been able to get non-approved commands to [consistently] work. Well, technically when it is running pwsh sequenced commands, all commands are available and msbuild does work/run (the downside being there being every single read/search etc prompts for approval). That aside, codex-cli keeps butting up against some kind of whitelisted allowlist but I can't find a config on how to set.

--

ls.cmd (shim for better ls)
<details>

@echo off
REM --- ls shim for cmd.exe / PowerShell-aware --------------------------------
REM Behavior:
REM - If running under PowerShell (parent or grandparent process is powershell.exe or pwsh.exe)
REM     * If args contain known Unix ls flags then call msls %*
REM     * Else if args contain known Get-ChildItem flags then call Get-ChildItem %*
REM     * Else with no flags call Get-ChildItem %*   default in PowerShell
REM - If running under cmd.exe
REM     * If msls exists then call msls --color=auto -alhpF %*
REM     * Else call dir %*
REM ---------------------------------------------------------------------------

setlocal EnableExtensions EnableDelayedExpansion

REM Detect msls
where msls >nul 2>nul
set "HAVE_MSLS=0"
if %ERRORLEVEL% EQU 0 set "HAVE_MSLS=1"

REM Compute whether this CMD was started with /c which indicates a one-shot trampoline call
REM Use string substitution instead of piping CMDCMDLINE to findstr to avoid noise from quotes and meta chars
set "IS_CMD_C=0"
set "CMDCMD=%CMDCMDLINE%"
set "CMDCMD=%CMDCMD:"=%"
REM strip quotes so /c" becomes /c
set "CMDCMD=%CMDCMD% "
REM pad trailing space so end-of-line matches become ' /c '
if not "%CMDCMD: /c =%"=="%CMDCMD%" set "IS_CMD_C=1"
if not "%CMDCMD: /C =%"=="%CMDCMD%" set "IS_CMD_C=1"

REM Detect if invoked from PowerShell. Prefer CIM via PowerShell or pwsh. Keep WMIC fallback.
set "IN_POWERSHELL=0"
set "SELF=%~f0"

REM Prefer pwsh, then Windows PowerShell
set "PSHOST="
where pwsh >nul 2>nul && set "PSHOST=pwsh"
if not defined PSHOST ( where powershell >nul 2>nul && set "PSHOST=powershell" )

if defined PSHOST (
  "%PSHOST%" -NoProfile -NoLogo -ExecutionPolicy Bypass -Command ^
    "$pp=(Get-CimInstance Win32_Process -Filter ('ProcessId={0}' -f $PID)).ParentProcessId;" ^
    "$me=Get-CimInstance Win32_Process -Filter ('ProcessId={0}' -f $pp);" ^
    "$p =Get-CimInstance Win32_Process -Filter ('ProcessId={0}' -f $me.ParentProcessId);" ^
    "if ($p.Name -eq 'conhost.exe') { $p=Get-CimInstance Win32_Process -Filter ('ProcessId={0}' -f $p.ParentProcessId) }" ^
    "if ($p.Name -match '^(pwsh|powershell)\.exe$') { exit 0 } else { exit 1 }" >nul

  REM Use delayed expansion and only treat as PowerShell when this CMD was started with /c
  if !ERRORLEVEL! EQU 0 if "!IS_CMD_C!"=="1" set "IN_POWERSHELL=1"
)

REM Legacy WMIC fallback only if not already determined
if "!IN_POWERSHELL!"=="0" (
  set "PPID="
  set "PPNAME="
  set "GPPID="
  set "GPPNAME="

  where wmic >nul 2>nul
  if !ERRORLEVEL! EQU 0 (
    REM Find our current cmd.exe row by matching the command line with our script path
    for /f "skip=1 tokens=1,2,*" %%A in ('
      wmic process where "name='cmd.exe'" get ProcessId^,ParentProcessId^,CommandLine /format:table
    ') do (
      REM Columns: ProcessId  ParentProcessId  CommandLine
      echo(%%C | findstr /I /C:"%SELF%" >nul
      if not errorlevel 1 set "PPID=%%B"
    )
    if defined PPID (
      for /f "tokens=2 delims==" %%N in ('
        wmic process where "ProcessId=%PPID%" get Name /value ^| findstr "="
      ') do set "PPNAME=%%N"

      REM If parent is conhost.exe, walk up one more level to check its parent
      if /I "!PPNAME!"=="conhost.exe" (
        for /f "tokens=2 delims==" %%N in ('
          wmic process where "ProcessId=%PPID%" get ParentProcessId /value ^| findstr "="
        ') do set "GPPID=%%N"
        if defined GPPID (
          for /f "tokens=2 delims==" %%N in ('
            wmic process where "ProcessId=!GPPID!" get Name /value ^| findstr "="
          ') do set "GPPNAME=%%N"
        )
      )

      REM Only mark PowerShell when parent or grandparent is PS and this CMD was started with /c
      if /I "!PPNAME!"=="powershell.exe"  if "!IS_CMD_C!"=="1" set "IN_POWERSHELL=1"
      if /I "!PPNAME!"=="pwsh.exe"        if "!IS_CMD_C!"=="1" set "IN_POWERSHELL=1"
      if /I "!GPPNAME!"=="powershell.exe" if "!IS_CMD_C!"=="1" set "IN_POWERSHELL=1"
      if /I "!GPPNAME!"=="pwsh.exe"       if "!IS_CMD_C!"=="1" set "IN_POWERSHELL=1"
    )
  )
)

REM PowerShell-aware branch
if "!IN_POWERSHELL!"=="1" (
  REM Known GCI switches including common parameters
  set "GCI_LIST= Path LiteralPath Filter Include Exclude Recurse Force Depth Hidden Directory File Name Attributes System ReadOnly ErrorAction ErrorVariable OutVariable OutBuffer Verbose Debug WarningAction WarningVariable InformationAction InformationVariable WhatIf Confirm PipelineVariable "

  REM Known Unix long options to recognize
  set "UNIX_LONG= --color --all --long --human-readable --group-directories-first --classify --almost-all --time-style --quoting-style "

  set "HAS_UNIX=0"
  set "HAS_GCI=0"

  for %%A in (%*) do (
    set "arg=%%~A"
    if "!arg:~0,1!"=="-" (
      if "!arg:~0,2!"=="--" (
        for /f "tokens=1 delims==" %%K in ("!arg!") do set "opt=%%K"
        echo !UNIX_LONG! | findstr /I /C:" !opt! " >nul && set "HAS_UNIX=1"
      ) else (
        set "token=!arg:~1!"
        for /f "tokens=1 delims=:" %%K in ("!token!") do set "tname=%%K"
        echo !GCI_LIST! | findstr /I /C:" !tname! " >nul && set "HAS_GCI=1"
        if "!HAS_GCI!"=="0" (
          echo(!tname!| findstr /R "^[A-Za-z0-9][A-Za-z0-9]*$" >nul && set "HAS_UNIX=1"
        )
      )
    )
  )

  REM Choose runner for GCI
  set "PSRUN=!PSHOST!"
  if not defined PSRUN set "PSRUN=powershell"

  REM If Unix-style flags were used and msls exists, let msls handle them
  if "!HAVE_MSLS!"=="1" if "!HAS_UNIX!"=="1" (
    msls --color=auto -alhpF %*
    exit /b !ERRORLEVEL!
  )

  REM If GCI-style flags present, call Get-ChildItem
  if "!HAS_GCI!"=="1" (
    "!PSRUN!" -NoProfile -ExecutionPolicy Bypass -Command "Get-ChildItem @args" %*
    exit /b !ERRORLEVEL!
  )

  REM Default in PowerShell context is Get-ChildItem
  "!PSRUN!" -NoProfile -ExecutionPolicy Bypass -Command "Get-ChildItem @args" %*
  exit /b !ERRORLEVEL!
)

REM Plain cmd.exe branch
if "%HAVE_MSLS%"=="1" (
  msls --color=auto -alhpF %*
  exit /b !ERRORLEVEL!
)

dir %*
exit /b !ERRORLEVEL!

</details>

msbuild.cmd (shim for msbuild)
<details>

@echo off
rem ---------------------------------------------------------------------------
rem msbuild.cmd - file-based shim that locates and invokes the preferred MSBuild
rem Priority:
rem   (1) 64-bit (amd64) first, then 32-bit
rem   (2) Visual Studio (Community) before Build Tools
rem   (3) Newest installation (by year folder, e.g., 2025 > 2022 > 2019)
rem
rem Always verbose:
rem   - This shim unconditionally enables MSBUILD_SHIM_VERBOSE=1.
rem Optional toggle:
rem   - Set MSBUILD_ARCH=x86 to prefer 32-bit first (default is x64)
rem ---------------------------------------------------------------------------
setlocal
set "MSBUILD_SHIM_VERBOSE=1"

rem Choose architecture preference (default x64/amd64)
set "ARCHPAT=amd64"
if /i "%MSBUILD_ARCH%"=="x86" set "ARCHPAT="

rem Locate vswhere (installed with VS 2017+). If absent, we'll do manual search.
set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
if not exist "%VSWHERE%" (
  for %%V in (vswhere.exe) do set "VSWHERE=%%~$PATH:V"
)

rem --- Try vswhere-based discovery first -----------------------------------------
if exist "%VSWHERE%" (
  rem Visual Studio (Community/Pro/Enterprise) first
  call :FIND_MSBUILD "Microsoft.VisualStudio.Product.Enterprise Microsoft.VisualStudio.Product.Professional Microsoft.VisualStudio.Product.Community" "%ARCHPAT%" MSBUILD
  if defined MSBUILD goto :RUN

  rem Build Tools next
  call :FIND_MSBUILD "Microsoft.VisualStudio.Product.BuildTools" "%ARCHPAT%" MSBUILD
  if defined MSBUILD goto :RUN

  rem If x64-first failed, retry allowing 32-bit under the same products
  if /i not "%MSBUILD_ARCH%"=="x86" (
    call :FIND_MSBUILD "Microsoft.VisualStudio.Product.Enterprise Microsoft.VisualStudio.Product.Professional Microsoft.VisualStudio.Product.Community" "" MSBUILD
    if defined MSBUILD goto :RUN

    call :FIND_MSBUILD "Microsoft.VisualStudio.Product.BuildTools" "" MSBUILD
    if defined MSBUILD goto :RUN
  )
)

rem --- Manual ("legacy") search by explicit path patterns, dynamic year ------------
rem Matches these types of paths (year is dynamic: 20*), newest year first:
rem   C:\Program Files\Microsoft Visual Studio\<YEAR>\Community\MSBuild\Current\Bin\amd64\MSBuild.exe
rem   C:\Program Files\Microsoft Visual Studio\<YEAR>\Community\MSBuild\Current\Bin\MSBuild.exe
rem   C:\Program Files (x86)\Microsoft Visual Studio\<YEAR>\BuildTools\MSBuild\Current\Bin\amd64\MSBuild.exe
rem   C:\Program Files (x86)\Microsoft Visual Studio\<YEAR>\BuildTools\MSBuild\Current\Bin\MSBuild.exe
call :FIND_MSBUILD_MANUAL "%ARCHPAT%" MSBUILD
if defined MSBUILD goto :RUN

rem If we preferred x64 and didn't find it, try 32-bit equivalents for the same patterns
if /i not "%MSBUILD_ARCH%"=="x86" (
  call :FIND_MSBUILD_MANUAL "" MSBUILD
  if defined MSBUILD goto :RUN
)

rem --- Final fallback to legacy .NET Framework MSBuild ----------------------------
:LEGACY
set "MSBUILD=%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe"
if exist "%MSBUILD%" goto :RUN
set "MSBUILD=%WINDIR%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe"
if exist "%MSBUILD%" goto :RUN

>&2 echo [msbuild.cmd] ERROR: Unable to locate MSBuild.exe.
exit /b 9009

:RUN
if defined MSBUILD_SHIM_VERBOSE echo [msbuild.cmd] Using: "%MSBUILD%"
"%MSBUILD%" %*
set "code=%errorlevel%"
exit /b %code%

rem ------------------------------------------------------------------------------
rem :FIND_MSBUILD <products> <archpat> <outvar>
rem Uses vswhere to find the newest instance with MSBuild, optionally preferring amd64.
rem ------------------------------------------------------------------------------
:FIND_MSBUILD
setlocal
set "PRODUCTS=%~1"
set "ARCHPAT=%~2"
set "OUTVAR=%~3"

if defined ARCHPAT (
  for /f "usebackq delims=" %%P in ( `
    "%VSWHERE%" -latest -products %PRODUCTS% -requires Microsoft.Component.MSBuild ^
      -find MSBuild\**\Bin\amd64\MSBuild.exe
  ` ) do (
    endlocal & set "%OUTVAR%=%%P" & goto :EOF
  )
)

for /f "usebackq delims=" %%P in ( `
  "%VSWHERE%" -latest -products %PRODUCTS% -requires Microsoft.Component.MSBuild ^
    -find MSBuild\**\Bin\MSBuild.exe
` ) do (
  endlocal & set "%OUTVAR%=%%P" & goto :EOF
)

endlocal & set "%OUTVAR%=" & goto :EOF

rem ------------------------------------------------------------------------------
rem :FIND_MSBUILD_MANUAL <archpat> <outvar>
rem Manual path search by the specific patterns requested, with dynamic year folder.
rem Checks Community (Program Files) first, then Build Tools (Program Files x86).
rem Within each, prefers amd64 (if ARCHPAT is set), then 32-bit, and years newest first.
rem ------------------------------------------------------------------------------
:FIND_MSBUILD_MANUAL
setlocal
set "ARCHPAT=%~1"
set "OUTVAR=%~2"

rem --- 1) Community under Program Files ------------------------------------------
for /f "usebackq delims=" %%Y in ( `
  dir /b /ad /o-n "%ProgramFiles%\Microsoft Visual Studio\20*" 2^>nul
` ) do (
  if defined ARCHPAT (
    if exist "%ProgramFiles%\Microsoft Visual Studio\%%Y\Community\MSBuild\Current\Bin\amd64\MSBuild.exe" (
      endlocal & set "%OUTVAR%=%ProgramFiles%\Microsoft Visual Studio\%%Y\Community\MSBuild\Current\Bin\amd64\MSBuild.exe" & goto :EOF
    )
  )
  if exist "%ProgramFiles%\Microsoft Visual Studio\%%Y\Community\MSBuild\Current\Bin\MSBuild.exe" (
    endlocal & set "%OUTVAR%=%ProgramFiles%\Microsoft Visual Studio\%%Y\Community\MSBuild\Current\Bin\MSBuild.exe" & goto :EOF
  )
)

rem --- 2) Build Tools under Program Files (x86) ----------------------------------
if defined ProgramFiles(x86) (
  for /f "usebackq delims=" %%Y in ( `
    dir /b /ad /o-n "%ProgramFiles(x86)%\Microsoft Visual Studio\20*" 2^>nul
  ` ) do (
    if defined ARCHPAT (
      if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\%%Y\BuildTools\MSBuild\Current\Bin\amd64\MSBuild.exe" (
        endlocal & set "%OUTVAR%=%ProgramFiles(x86)%\Microsoft Visual Studio\%%Y\BuildTools\MSBuild\Current\Bin\amd64\MSBuild.exe" & goto :EOF
      )
    )
    if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\%%Y\BuildTools\MSBuild\Current\Bin\MSBuild.exe" (
      endlocal & set "%OUTVAR%=%ProgramFiles(x86)%\Microsoft Visual Studio\%%Y\BuildTools\MSBuild\Current\Bin\MSBuild.exe" & goto :EOF
    )
  )
)

endlocal & set "%OUTVAR%=" & goto :EOF

</details>
</details>

Where did you find it?

_No response_

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗