`Allowlist` config ? `tried to run {command}, but this environment’s command allowlist blocked it`
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 topwshandcmdshells and I have mademsbuild,sed,grep,rg,ls,jq,less,curl, andwgetcommands 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:
- 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
- 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}
- 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.
lsin 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
> }
> }
- About once out of every ~10 runs the model tries approach of using separate
pwshcommands (which wants approval on every single one). Closing and starting the session over usually solves this for me,.
- I have not seemingly been able to get non-approved commands to [consistently] work. Well, technically when it is running
pwshsequenced 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_
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗