Skip to content

Harden the pkgxray-guard install-gate (git-URL, fail-mode, cache, edit-diff) - #18

Open
adamsjack711-ux wants to merge 7 commits into
CorridorSecurity:mainfrom
adamsjack711-ux:pkgxray-guard/harden-install-gate
Open

Harden the pkgxray-guard install-gate (git-URL, fail-mode, cache, edit-diff)#18
adamsjack711-ux wants to merge 7 commits into
CorridorSecurity:mainfrom
adamsjack711-ux:pkgxray-guard/harden-install-gate

pkgxray-guard: harden subprocess spawns (gosec G204) with ref validation

0e15888
Select commit
Loading
Failed to load commit list.
Corridor Security / Corridor Review failed Jul 2, 2026 in 1m 8s

Merge blocked — 4 open findings (2 high, 2 medium severity)

4 open findings block merging this PR (2 high, 2 medium severity).

Corridor re-checks remediation after each push before updating this status.

To unblock, reply to any finding comment with:
unblock — override and merge anyway
false positive — mark as not applicable

Or push a fix — remediated findings close automatically and this check updates.

Finished in 43s

Details

Open findings

  1. High — <untrusted_finding_50291053f307>
    examples/pkgxray-guard/main.go
    </untrusted_finding_50291053f307>: <untrusted_finding_29afaaaa34eb>
    Command argument injection in examples/pkgxray-guard/main.go
    </untrusted_finding_29afaaaa34eb>
    <untrusted_finding_192d784e256b>
    In auditManifestFile (main.go:225), the filePath argument originates from ctx.FilePath, which reflects the file path reported by the AI agent's tool call. It is passed as a positional argument to exec.Command("pkgxray", "audit", filePath) without an end-of-options -- marker. Although Go's exec.Command avoids shell injection by passing arguments directly to execve, many CLI argument parsers (POSIX getopt, Go's flag, cobra, Python's argparse) will interpret any argument beginn…
    </untrusted_finding_192d784e256b>

  2. High — <untrusted_finding_0df66de33944>
    examples/pkgxray-guard/pkgxrayguard/parse.go:79-96
    </untrusted_finding_0df66de33944>: <untrusted_finding_fc4d20c1edf2>
    Protection mechanism bypass in examples/pkgxray-guard/pkgxrayguard/parse.go
    </untrusted_finding_fc4d20c1edf2>
    <untrusted_finding_4909c2b8d7f5>
    The parseSegment function resolves the binary name from toks[0] only. Shell-level env-var assignments (FOO=1 npm install pkg) place FOO=1 at toks[0], making path.Base(toks[0]) equal to FOO=1 — no switch case matches and the function returns nil. The same logic fails for env npm install pkg (first token is env), command npm install pkg (first token is command), and the npm runner aliases npm exec pkg / npm x pkg (which are never listed in the switch). Because `OnBefor…
    </untrusted_finding_4909c2b8d7f5>

  3. Medium — <untrusted_finding_baa9411e2108>
    examples/pkgxray-guard/main.go:225-236
    </untrusted_finding_baa9411e2108>: <untrusted_finding_303b225794f9>
    Path traversal in examples/pkgxray-guard/main.go
    </untrusted_finding_303b225794f9>
    <untrusted_finding_b0f447058976>
    OnAfterFileEdit receives ctx.FilePath directly from the AI agent's tool-use JSON payload (the file_path field of a Claude Code Write or Edit call, or equivalent on Droid/Cursor/Cascade/Codex). The guard at line 54 of main.go only calls isDependencyManifest(ctx.FilePath), which resolves to dependencyManifests[filepath.Base(filePath)] — a basename-only check. A path such as ../../other-project/package.json has a basename of package.json, so it passes the allowlist, and ctx.FilePath is forwarded u…
    </untrusted_finding_b0f447058976>

  4. Medium — <untrusted_finding_c7f475d4fa8a>
    examples/pkgxray-guard/pkgxrayguard/cache.go:40-42
    </untrusted_finding_c7f475d4fa8a>: <untrusted_finding_f1987a74304c>
    Protection mechanism bypass in examples/pkgxray-guard/pkgxrayguard/cache.go
    </untrusted_finding_f1987a74304c>
    <untrusted_finding_6557d7ec8c8d>
    MemoGuard.Check stores and returns the full Result struct, which includes the Spec from the original request. The cache key is spec.Ref only (e.g. npm:evil-pkg@1.0.0). If a persistent-install form (npm install evil-pkg, Immediate=false) is checked first and returns verdict Review, this Result is cached. A subsequent runner invocation (npx evil-pkg, Immediate=true) hits the cache and receives the stale Result with Spec.Immediate=false. DecideResult (policy.go:47) then…
    </untrusted_finding_6557d7ec8c8d>

Annotations

Check failure on line 225 in examples/pkgxray-guard/main.go

See this annotation in the file changed.

@corridor-security corridor-security / Corridor Review

High: <untrusted_finding_1aad7a983bca> Command argument injection in examples/pkgxray-guard/main.go </untrusted_finding_1aad7a983bca>

<untrusted_finding_d7322df61af6>
In `auditManifestFile` (main.go:225), the `filePath` argument originates from `ctx.FilePath`, which reflects the file path reported by the AI agent's tool call. It is passed as a positional argument to `exec.Command("pkgxray", "audit", filePath)` without an end-of-options `--` marker. Although Go's `exec.Command` avoids shell injection by passing arguments directly to `execve`, many CLI argument parsers (POSIX getopt, Go's `flag`, `cobra`, Python's `argparse`) will interpret any argument beginn…
</untrusted_finding_d7322df61af6>

Check failure on line 96 in examples/pkgxray-guard/pkgxrayguard/parse.go

See this annotation in the file changed.

@corridor-security corridor-security / Corridor Review

High: <untrusted_finding_501d607098dd> Protection mechanism bypass in examples/pkgxray-guard/pkgxrayguard/parse.go </untrusted_finding_501d607098dd>

<untrusted_finding_c3f9f49e9a2c>
The `parseSegment` function resolves the binary name from `toks[0]` only. Shell-level env-var assignments (`FOO=1 npm install pkg`) place `FOO=1` at `toks[0]`, making `path.Base(toks[0])` equal to `FOO=1` — no switch case matches and the function returns `nil`. The same logic fails for `env npm install pkg` (first token is `env`), `command npm install pkg` (first token is `command`), and the npm runner aliases `npm exec pkg` / `npm x pkg` (which are never listed in the switch). Because `OnBefor…
</untrusted_finding_c3f9f49e9a2c>

Check warning on line 236 in examples/pkgxray-guard/main.go

See this annotation in the file changed.

@corridor-security corridor-security / Corridor Review

Medium: <untrusted_finding_2b08a90cfd3a> Path traversal in examples/pkgxray-guard/main.go </untrusted_finding_2b08a90cfd3a>

<untrusted_finding_be11c945dd42>
OnAfterFileEdit receives ctx.FilePath directly from the AI agent's tool-use JSON payload (the file_path field of a Claude Code Write or Edit call, or equivalent on Droid/Cursor/Cascade/Codex). The guard at line 54 of main.go only calls isDependencyManifest(ctx.FilePath), which resolves to dependencyManifests[filepath.Base(filePath)] — a basename-only check. A path such as ../../other-project/package.json has a basename of package.json, so it passes the allowlist, and ctx.FilePath is forwarded u…
</untrusted_finding_be11c945dd42>

Check warning on line 42 in examples/pkgxray-guard/pkgxrayguard/cache.go

See this annotation in the file changed.

@corridor-security corridor-security / Corridor Review

Medium: <untrusted_finding_5f6bbc34698d> Protection mechanism bypass in examples/pkgxray-guard/pkgxrayguard/cache.go </untrusted_finding_5f6bbc34698d>

<untrusted_finding_45f33c53d23b>
`MemoGuard.Check` stores and returns the full `Result` struct, which includes the `Spec` from the original request. The cache key is `spec.Ref` only (e.g. `npm:evil-pkg@1.0.0`). If a persistent-install form (`npm install evil-pkg`, `Immediate=false`) is checked first and returns verdict `Review`, this `Result` is cached. A subsequent runner invocation (`npx evil-pkg`, `Immediate=true`) hits the cache and receives the stale `Result` with `Spec.Immediate=false`. `DecideResult` (policy.go:47) then…
</untrusted_finding_45f33c53d23b>

Check failure on line 225 in examples/pkgxray-guard/main.go

See this annotation in the file changed.

@corridor-security corridor-security / Corridor Review

High: <untrusted_finding_fc2a4a661196> Command argument injection in examples/pkgxray-guard/main.go </untrusted_finding_fc2a4a661196>

<untrusted_finding_7d987a3608aa>
In `auditManifestFile` (main.go:225), the `filePath` argument originates from `ctx.FilePath`, which reflects the file path reported by the AI agent's tool call. It is passed as a positional argument to `exec.Command("pkgxray", "audit", filePath)` without an end-of-options `--` marker. Although Go's `exec.Command` avoids shell injection by passing arguments directly to `execve`, many CLI argument parsers (POSIX getopt, Go's `flag`, `cobra`, Python's `argparse`) will interpret any argument beginn…
</untrusted_finding_7d987a3608aa>

Check failure on line 96 in examples/pkgxray-guard/pkgxrayguard/parse.go

See this annotation in the file changed.

@corridor-security corridor-security / Corridor Review

High: <untrusted_finding_f3627bff47a6> Protection mechanism bypass in examples/pkgxray-guard/pkgxrayguard/parse.go </untrusted_finding_f3627bff47a6>

<untrusted_finding_bf6ff4c2a719>
The `parseSegment` function resolves the binary name from `toks[0]` only. Shell-level env-var assignments (`FOO=1 npm install pkg`) place `FOO=1` at `toks[0]`, making `path.Base(toks[0])` equal to `FOO=1` — no switch case matches and the function returns `nil`. The same logic fails for `env npm install pkg` (first token is `env`), `command npm install pkg` (first token is `command`), and the npm runner aliases `npm exec pkg` / `npm x pkg` (which are never listed in the switch). Because `OnBefor…
</untrusted_finding_bf6ff4c2a719>

Check warning on line 236 in examples/pkgxray-guard/main.go

See this annotation in the file changed.

@corridor-security corridor-security / Corridor Review

Medium: <untrusted_finding_cb2253a1a22c> Path traversal in examples/pkgxray-guard/main.go </untrusted_finding_cb2253a1a22c>

<untrusted_finding_83c59b63a71b>
OnAfterFileEdit receives ctx.FilePath directly from the AI agent's tool-use JSON payload (the file_path field of a Claude Code Write or Edit call, or equivalent on Droid/Cursor/Cascade/Codex). The guard at line 54 of main.go only calls isDependencyManifest(ctx.FilePath), which resolves to dependencyManifests[filepath.Base(filePath)] — a basename-only check. A path such as ../../other-project/package.json has a basename of package.json, so it passes the allowlist, and ctx.FilePath is forwarded u…
</untrusted_finding_83c59b63a71b>

Check warning on line 42 in examples/pkgxray-guard/pkgxrayguard/cache.go

See this annotation in the file changed.

@corridor-security corridor-security / Corridor Review

Medium: <untrusted_finding_2ad3f86326b4> Protection mechanism bypass in examples/pkgxray-guard/pkgxrayguard/cache.go </untrusted_finding_2ad3f86326b4>

<untrusted_finding_b032049166a6>
`MemoGuard.Check` stores and returns the full `Result` struct, which includes the `Spec` from the original request. The cache key is `spec.Ref` only (e.g. `npm:evil-pkg@1.0.0`). If a persistent-install form (`npm install evil-pkg`, `Immediate=false`) is checked first and returns verdict `Review`, this `Result` is cached. A subsequent runner invocation (`npx evil-pkg`, `Immediate=true`) hits the cache and receives the stale `Result` with `Spec.Immediate=false`. `DecideResult` (policy.go:47) then…
</untrusted_finding_b032049166a6>

Check failure on line 225 in examples/pkgxray-guard/main.go

See this annotation in the file changed.

@corridor-security corridor-security / Corridor Review

High: <untrusted_finding_3acf2c5867f9> Command argument injection in examples/pkgxray-guard/main.go </untrusted_finding_3acf2c5867f9>

<untrusted_finding_70d842d1a4f6>
In `auditManifestFile` (main.go:225), the `filePath` argument originates from `ctx.FilePath`, which reflects the file path reported by the AI agent's tool call. It is passed as a positional argument to `exec.Command("pkgxray", "audit", filePath)` without an end-of-options `--` marker. Although Go's `exec.Command` avoids shell injection by passing arguments directly to `execve`, many CLI argument parsers (POSIX getopt, Go's `flag`, `cobra`, Python's `argparse`) will interpret any argument beginn…
</untrusted_finding_70d842d1a4f6>

Check failure on line 96 in examples/pkgxray-guard/pkgxrayguard/parse.go

See this annotation in the file changed.

@corridor-security corridor-security / Corridor Review

High: <untrusted_finding_6557ed019a24> Protection mechanism bypass in examples/pkgxray-guard/pkgxrayguard/parse.go </untrusted_finding_6557ed019a24>

<untrusted_finding_5a460f37d0b3>
The `parseSegment` function resolves the binary name from `toks[0]` only. Shell-level env-var assignments (`FOO=1 npm install pkg`) place `FOO=1` at `toks[0]`, making `path.Base(toks[0])` equal to `FOO=1` — no switch case matches and the function returns `nil`. The same logic fails for `env npm install pkg` (first token is `env`), `command npm install pkg` (first token is `command`), and the npm runner aliases `npm exec pkg` / `npm x pkg` (which are never listed in the switch). Because `OnBefor…
</untrusted_finding_5a460f37d0b3>

Check warning on line 236 in examples/pkgxray-guard/main.go

See this annotation in the file changed.

@corridor-security corridor-security / Corridor Review

Medium: <untrusted_finding_b6a02904811b> Path traversal in examples/pkgxray-guard/main.go </untrusted_finding_b6a02904811b>

<untrusted_finding_358aae30ed93>
OnAfterFileEdit receives ctx.FilePath directly from the AI agent's tool-use JSON payload (the file_path field of a Claude Code Write or Edit call, or equivalent on Droid/Cursor/Cascade/Codex). The guard at line 54 of main.go only calls isDependencyManifest(ctx.FilePath), which resolves to dependencyManifests[filepath.Base(filePath)] — a basename-only check. A path such as ../../other-project/package.json has a basename of package.json, so it passes the allowlist, and ctx.FilePath is forwarded u…
</untrusted_finding_358aae30ed93>

Check warning on line 42 in examples/pkgxray-guard/pkgxrayguard/cache.go

See this annotation in the file changed.

@corridor-security corridor-security / Corridor Review

Medium: <untrusted_finding_996f64b32de2> Protection mechanism bypass in examples/pkgxray-guard/pkgxrayguard/cache.go </untrusted_finding_996f64b32de2>

<untrusted_finding_13d4dfbabce2>
`MemoGuard.Check` stores and returns the full `Result` struct, which includes the `Spec` from the original request. The cache key is `spec.Ref` only (e.g. `npm:evil-pkg@1.0.0`). If a persistent-install form (`npm install evil-pkg`, `Immediate=false`) is checked first and returns verdict `Review`, this `Result` is cached. A subsequent runner invocation (`npx evil-pkg`, `Immediate=true`) hits the cache and receives the stale `Result` with `Spec.Immediate=false`. `DecideResult` (policy.go:47) then…
</untrusted_finding_13d4dfbabce2>