[Windows][Codex Security 0.1.18] Deep Scan fails because in-scope inventory preserves .\ paths

Open 💬 1 comment Opened Aug 7, 2026 by Foo-Fighter

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:

  1. require repository-relative paths;
  2. reject absolute paths;
  3. reject .. traversal components;
  4. remove . components;
  5. 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

View original on GitHub ↗

1 Comment

Ben2248 · 15 days ago

+1