[Windows][Codex Security 0.1.18] Deep Scan fails because in-scope inventory preserves .\ paths
What version of the Codex App are you using (From “About Codex” dialog)?
26.803.41515
What subscription do you have?
ChatGPT Business
What platform is your computer?
Microsoft Windows NT 10.0.26200.0 x64
What issue are you seeing?
Codex Security Deep Scan fails on Windows before discovery because codex-security 0.1.18 writes the native Windows path spelling returned by ripgrep directly into its in-scope inventory.
With repository scope ., the Codex-bundled ripgrep 15.2.0 returns paths such as:
.\src\example.txt
codex-security/0.1.18/scripts/generate_in_scope_files.py preserves this value unchanged.
The relevant implementation invokes:
command = ["rg", "--files", "--hidden", "--glob", "!.git/**", "--", scope]
The resulting inventory is then only rewound and sorted:
inventory.seek(0)
rows = sorted(inventory)
and written unchanged:
handle.writelines(rows)
There is no platform-independent path canonicalization between the ripgrep output and the inventory writer.
In the affected Deep Security Scan, downstream inventory validation rejected the generated Windows-formatted entries because they contained backslashes and leading . path segments.
The scan failure analysis reported:
- 1,182 generated in-scope paths
- 1,182 paths violating the inventory path requirements
- terminal scan status:
failed - failure before discovery workers started
The failed logical Deep Scan could not be resumed.
Environment:
- Codex App (About dialog):
26.803.41515 - MSIX/AppX package:
OpenAI.Codex 26.803.5235.0 - Embedded Codex CLI:
codex-cli 0.147.0-alpha.6.5 - Codex Security plugin:
0.1.18 - Codex-bundled ripgrep:
ripgrep 15.2.0 (rev e89fff89ac) - PowerShell:
7.6.4 - Windows x64
No repository files were modified during reproduction or diagnosis.
What steps can reproduce the bug?
The faulty inventory serialization can be reproduced without the original repository and without starting another Security Scan.
1. Create an isolated temporary test directory
$TestRoot = Join-Path $env:TEMP "codex-rg-path-test"
Remove-Item $TestRoot -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory $TestRoot | Out-Null
New-Item -ItemType Directory (Join-Path $TestRoot "src") | Out-Null
"test" | Set-Content (Join-Path $TestRoot "src\example.txt")
2. Locate the ripgrep binary bundled with Codex
The affected Codex installation contains its own rg.exe.
A portable way to locate it is:
$Rg = Get-ChildItem "$env:LOCALAPPDATA\OpenAI\Codex\bin" `
-Filter "rg.exe" `
-File `
-Recurse `
-ErrorAction Stop |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1 -ExpandProperty FullName
& $Rg --version
Observed version:
ripgrep 15.2.0 (rev e89fff89ac)
features:+pcre2
simd(compile):+SSE2,-SSSE3,-AVX2
simd(runtime):+SSE2,+SSSE3,+AVX2
PCRE2 10.45 is available (JIT is available)
3. Run the same ripgrep arguments used by the plugin
Push-Location $TestRoot
try {
$Rows = @(& $Rg --files --hidden --glob "!.git/**" -- .)
Write-Host "Raw ripgrep output:"
$Rows
Write-Host "`nBackslash count:"
@($Rows | Where-Object { $_ -match '\\' }).Count
Write-Host "`nLeading dot-segment count:"
@($Rows | Where-Object { $_ -match '^\.[\\/]' }).Count
Write-Host "`nRows:"
$Rows.Count
}
finally {
Pop-Location
}
Observed output:
Raw ripgrep output:
.\src\example.txt
Backslash count:
1
Leading dot-segment count:
1
Rows:
1
This confirms that the Codex-bundled ripgrep returns the native Windows path spelling for repository scope ..
4. Run the actual Codex Security inventory generator
Use the actual generator from Codex Security 0.1.18:
codex-security/0.1.18/scripts/generate_in_scope_files.py
The script invokes rg by name, so make the directory containing Codex's bundled rg.exe available only to the current PowerShell process for the
duration of this test:
$OldPath = $env:PATH
try {
$env:PATH = "$(Split-Path $Rg);$env:PATH"
$PluginScript = "$env:USERPROFILE\.codex\plugins\cache\openai-curated-remote\codex-security\0.1.18\scripts\generate_in_scope_files.py"
$OutputFile = Join-Path $TestRoot "inventory.txt"
Remove-Item $OutputFile -Force -ErrorAction SilentlyContinue
python $PluginScript `
--repo $TestRoot `
--scope "." `
--out $OutputFile
$InventoryRows = @(Get-Content $OutputFile)
Write-Host "`nGenerated inventory:"
$InventoryRows
Write-Host "`nBackslash count:"
@($InventoryRows | Where-Object { $_ -match '\\' }).Count
Write-Host "`nLeading dot-segment count:"
@($InventoryRows | Where-Object { $_ -match '^\.[\\/]' }).Count
Write-Host "`nRows:"
$InventoryRows.Count
}
finally {
$env:PATH = $OldPath
}
Observed output:
Recorded 1 in-scope files.
Generated inventory:
.\src\example.txt
Backslash count:
1
Leading dot-segment count:
1
Rows:
1
This demonstrates that generate_in_scope_files.py preserves the native Windows ripgrep path spelling unchanged.
The real Deep Scan subsequently failed when its downstream inventory validation processed the same path representation.
What is the expected behavior?
Codex Security should serialize in-scope inventory entries into a canonical, repository-relative representation independent of the host operating system.
For example:
.\src\example.txt
should be serialized as:
src/example.txt
The generated inventory should contain:
- repository-relative paths
/path separators- no
.path components - no
..traversal components - no absolute paths
The same repository and scan scope should produce equivalent canonical inventory semantics on Windows and POSIX hosts.
A Deep Security Scan should not enter terminal failed state before discovery because of host-specific path spelling produced by its bundled search tool.
Additional information
resolve_scope() also contributes to this behavior because relative scopes are returned unchanged:
def resolve_scope(repository: Path, value: str) -> str:
...
if requested.is_absolute():
return relative.as_posix() if relative.parts else "."
return value
Therefore the normal repository-root scope:
.
remains "." and is passed directly to ripgrep.
The relevant generator flow is therefore:
scope "."
|
v
rg --files --hidden --glob !.git/** -- .
|
v
.\src\example.txt
|
v
inventory.seek(0)
rows = sorted(inventory)
|
v
handle.writelines(rows)
|
v
.\src\example.txt
|
v
downstream inventory validation
|
v
Deep Scan FAILED
Suggested fix
Canonicalize and validate every path returned by ripgrep before writing the inventory.
A simple string replacement alone should not be the complete security boundary. The canonicalization should:
- require repository-relative paths;
- reject absolute paths;
- reject
..traversal components; - remove
.components; - serialize with
/separators.
For example:
Raw Windows result:
.\src\subdir\file.py
Canonical inventory:
src/subdir/file.py
Suggested regression tests
Windows repository-root scope
Input:
.\src\file.py
Expected:
src/file.py
Nested Windows path
Input:
.\src\subdir\file.py
Expected:
src/subdir/file.py
Inventory invariants
Assert:
backslashes = 0
"." path segments = 0
".." segments = 0
absolute paths = 0
Cross-platform invariant
The same repository and scope should produce equivalent canonical inventory entries on Windows, Linux, and macOS.
Impact observed in the real scan
The affected Deep Security Scan reported:
- 1,182 generated inventory entries
- 1,182 entries violating the validator's path requirements
- terminal state
failed - failure before discovery workers started
- no usable Deep Scan result
- the failed logical scan could not be resumed
This is particularly disruptive because setup/model usage can be consumed before actual security discovery begins, and a replacement scan must be started after remediation.
Separate Windows sandbox issue
Windows sandbox / command-runner fallback approval messages were also observed during the same Codex session.
Those appear to be a separate Windows Codex issue and are intentionally excluded
from this report so that the inventory path bug remains independently reproducible and attributable.
Additional version information:
- MSIX/AppX package:
OpenAI.Codex 26.803.5235.0 - Embedded Codex CLI:
codex-cli 0.147.0-alpha.6.5
1 Comment
+1