Add vuln-hunt regression tests across builtins and shell features#264
Conversation
This comment has been minimized.
This comment has been minimized.
|
@codex review this PR Please use the following severity format for all findings:
Prefix each finding title with its priority label, e.g. "P0: ...", "P1: ...", etc. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 76783186da
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
AlexandreYang
left a comment
There was a problem hiding this comment.
Self-review (iteration 1)
This PR is purely additive tests, but several of the new tests are currently failing in CI on one or more platforms. The failures are real defects in the test files themselves, not in the shell — the tests need to be fixed (or marked platform-specific) before merge.
Findings
| # | Priority | File | Finding |
|---|---|---|---|
| 1 | tests/scenarios/cmd/break/hardening/input_redirect_ignored.yaml |
Test logic is broken: echo TOP SECRET is a literal echo, file path wrong, redirect always fails — test FAILs on all 3 platforms |
|
| 2 | tests/scenarios/cmd/continue/hardening/input_redirect_ignored.yaml |
Same broken pattern as #1; FAILs on all 3 platforms | |
| 3 | builtins/internal/procnetsocket/procnetsocket_vuln_hunt_test.go:60 |
validateProcPath("/proc") returns \proc on Windows; FAILs on windows-latest |
|
| 4 | interp/pipe_vuln_hunt_test.go:63 |
Windows broken-pipe error format differs (write |1: The pipe has been ended.); FAILs on windows-latest |
|
| 5 | tests/scenarios/shell/field_splitting/vuln_hunt/input_redirect_unquoted_var_not_field_split.yaml:22 |
stderr_contains uses /; Windows reports \; FAILs on windows-latest |
|
| 6 | builtins/cut/cut_unix_vuln_hunt_test.go:1 |
//go:build unix precedes the copyright header — compliance check FAILs |
|
| 7 | builtins/tr/tr_unix_vuln_hunt_test.go:1 |
Same build-tag/header ordering issue — compliance check FAILs | |
| 8 | analysis/*_vuln_hunt_test.go |
New files in analysis/ trigger Static Analysis Label Check; AGENTS.md guidance suggests automated workflows should not self-add verified/* labels — relocate the test or accept the gated check |
|
| 9 | builtins/internal/procsyskernel/procsyskernel_fifo_vuln_hunt_test.go:43 |
1-second FIFO timeout could flake under CI load |
Positive observations
- All new tests follow the project's
|+block scalar /expect.stderrconventions where applicable. - Hardening scenarios that intentionally diverge from bash (
AllowedPaths, blocked commands) correctly setskip_assert_against_bash: true. - Procnet/procpath unit tests have good split between Linux happy-path (
*_linux_*_test.go) and non-Linux refusal (*_other_*_test.go). - 144+ scenarios added without any regressions in untouched commands.
Overall assessment
Needs fixes — CI is red on all three platforms. All seven P1 findings are deterministic test bugs (broken assertions, missing platform guards, mis-ordered build tags); fixing them should turn CI green without touching shell behaviour.
|
Iteration 1 self-review — 9 findings: 7×P1, 1×P2, 1×P3 (P0_P1_P2_COUNT=8). The PR is currently red on CI; all P1 findings correspond to deterministic test failures on at least one platform (broken assertions in break/continue hardening YAML, missing Windows guards in procnetsocket / pipe_vuln_hunt / field_splitting tests, mis-ordered build tags in cut/tr unix tests). Review: #264 (review) |
- break/continue hardening yaml: use the file path inside allowed_paths so the redirect succeeds and the loop-control behaviour is actually exercised (previously the redirect failed and echo TOP SECRET ran). - procnetsocket_vuln_hunt_test.go: add //go:build !windows; validateProcPath returns \proc on Windows (filepath.Clean), so the test is unix-only. - pipe_vuln_hunt_test.go: skip PipeWriterStopsAfterReaderExit on Windows where the broken-pipe error format differs from unix. - field_splitting input_redirect_unquoted_var_not_field_split.yaml: add stderr_contains_windows for the backslash path separator. - cut/tr _unix_vuln_hunt_test.go: move //go:build unix below the copyright header to satisfy TestComplianceCopyrightHeaders. - procsyskernel FIFO test: bump 1s timeout to 2s for CI headroom.
|
@codex review this PR Please use the following severity format for all findings:
Prefix each finding title with its priority label, e.g. "P0: ...", "P1: ...", etc. |
AlexandreYang
left a comment
There was a problem hiding this comment.
Self-review (iteration 2)
Re-review against HEAD fac3064e — the iter-1 fix commit. The only changes since iter 1 are the 8 targeted test fixes that landed for the previously-flagged P1 findings. All three platform Test jobs now pass; compliance passes; bash-comparison passes.
Findings
None (P0_P1_P2_COUNT = 0).
Sanity-checked
- break/continue hardening yaml: redirect now points at
allowed/secret.txt— both scenarios now pass on all platforms. procnetsocket_vuln_hunt_test.go//go:build !windowscorrectly scopes the test off Windows;procnetsocket_other_vuln_hunt_test.go(!linux) still provides Windows non-Linux refusal coverage.interp/pipe_vuln_hunt_test.go:runtime.GOOS == "windows"skip is narrow to the one failing assertion (assert.Empty(stderr)); the other tests in the file still run on Windows.field_splitting/input_redirect_unquoted_var_not_field_split.yaml:stderr_contains_windows: ["one.txt allowed\\two.txt"]matches the framework's existing Windows-override pattern (confirmed:tests/scenarios_test.go:95defines the field, used elsewhere e.g.pwd/*.yaml).cut/tr _unix_vuln_hunt_test.go: build-tag-after-copyright ordering matches every other Go file in the repo and satisfiesTestComplianceCopyrightHeaders.- FIFO timeout 1s → 2s: low-risk hardening; FIFO rejection is fast-path so the bump only matters under unusual CI load.
Outstanding structural issue (carry-forward, not a new finding)
Static Analysis Label Checkstill fails because the PR modifies files underanalysis/(theverified/analysislabel is required). This is a deliberate human-review gate — the workflow message says "A human must review the changes and add the 'verified/analysis' label to this PR before it can be merged." Per AGENTS.md, AI does not self-addverified/*labels. The thread for this was acknowledged and resolved in iter 1; the CI check requires maintainer action.
Overall assessment
Safe to merge once the verified/analysis label is added by a maintainer. No code changes recommended.
|
Iteration 2 self-review — 0 findings (P0_P1_P2_COUNT=0). All iter-1 fixes verified: Test (ubuntu/macos/windows), compliance, and bash-comparison all pass. Only remaining CI failure is the manual-approval label gate ( Review: #264 (review) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fac3064e0c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| script: |+ | ||
| sed 's/hello/bye/' -- -secret.txt | ||
| expect: | ||
| stdout: "bye\n" |
There was a problem hiding this comment.
P3: Use |+ block scalars for scenario expectations
AGENTS.md requires input.script, expect.stdout, and expect.stderr values in scenario YAML to use the |+ block scalar even for single-line values. This new scenario uses a quoted scalar for stdout, and the same pattern appears in several other added scenarios, so please convert these expectation literals to |+ to keep the scenario suite in the documented format.
Useful? React with 👍 / 👎.
Review-Fix Loop Summary
Iteration log
Iter-1 fixes (commit
|
| File | Fix |
|---|---|
tests/scenarios/cmd/break/hardening/input_redirect_ignored.yaml |
Redirect now points at allowed/secret.txt (was outside allowed_paths) |
tests/scenarios/cmd/continue/hardening/input_redirect_ignored.yaml |
Same redirect-path fix |
builtins/internal/procnetsocket/procnetsocket_vuln_hunt_test.go |
//go:build !windows (filepath.Clean("/proc") returns \proc on Windows) |
interp/pipe_vuln_hunt_test.go |
t.Skip on Windows for the broken-pipe assertion (Windows error format differs) |
tests/scenarios/shell/field_splitting/vuln_hunt/input_redirect_unquoted_var_not_field_split.yaml |
Added stderr_contains_windows for backslash path separator |
builtins/cut/cut_unix_vuln_hunt_test.go |
Moved //go:build unix below copyright header (compliance) |
builtins/tr/tr_unix_vuln_hunt_test.go |
Same build-tag reorder |
builtins/internal/procsyskernel/procsyskernel_fifo_vuln_hunt_test.go |
1s → 2s FIFO timeout (CI-load hardening) |
Final state
- Unresolved threads: 0
- P0/P1/P2 findings: 0 (P3 findings are not blocking)
- CI: 39/40 checks passing; 1 failing —
Static Analysis Label Check(manual-approval gate foranalysis/directory changes)
Remaining issues
Static Analysis Label Check— requires a maintainer to review the two newanalysis/tripwire tests (callctx_openfile_vuln_hunt_test.go,signal_handling_vuln_hunt_test.go) and add theverified/analysislabel. The workflow's own error message states this must be a human action. Resolving this without maintainer involvement would defeat the gate.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fac3064e0c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| allowed := t.TempDir() | ||
| secret := t.TempDir() | ||
| require.NoError(t, os.Mkdir(filepath.Join(secret, "secret_dir"), 0755)) | ||
| require.NoError(t, os.Symlink(filepath.Join(secret, "secret_dir"), filepath.Join(allowed, "dir_link"))) |
There was a problem hiding this comment.
Skip symlink test when symlinks are unavailable
On Windows CI or other environments where creating symlinks requires elevated privileges, this require.NoError(os.Symlink(...)) fails during test setup before the regression is exercised. Other new symlink-based tests in this change either skip on Windows or skip when os.Symlink returns an error; this one should do the same to keep the cross-platform test suite green.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
In environments where the resolver does not immediately return NXDOMAIN for no-such-host-xyzzy.invalid, this test waits until the 5s context deadline and then fails; I reproduced this with go test -v ./builtins/ping -run 'TestPingPentest', which hit context deadline exceeded here and in the other new .invalid timeout tests. Because these tests run in the default suite rather than behind RSHELL_NET_TEST, go test ./... becomes dependent on local DNS behavior; use a deterministic numeric address with explicit short ping timeouts or another non-network-dependent input.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
What does this PR do?
Adds a large batch of regression tests from a vuln-hunt exercise (
[vuln-hunt 2026-05-19-codex]). All new files are tests — no behavioural changes to builtins or the interpreter. The tests exercise sandbox boundaries and confirm that attempted bypasses stay blocked across many surface areas:cut,echo,exit,grep,ping,printf,ps,read,sed,ss,strings,tr,true,uniq,wc): input redirects outsideAllowedPaths, symlink escapes, dash-prefixed filenames after--, output redirects blocked, unsupported flags rejected, numeric-arg overflow, etc.procnetsocket,procnetroute): direct unit tests covering Linux happy-path and non-Linux refusal.case_clause,globbing,logic_ops,pipe,signal_handling, plus scenario coverage forbrace_group,empty_script,field_splitting,for_clause,function,heredoc,allowed_commands,allowed_paths,blocked_commands): blocked chains, sandboxed expansion, command-substitution isolation, redirect / comment / metacharacter handling.Motivation
Capture findings from the 2026-05-19 vuln-hunt round as regression coverage so future refactors cannot silently regress sandbox guarantees.
Testing
go test ./...(all new tests pass).RSHELL_BASH_TEST=1 go test ./tests/ -run TestShellScenariosAgainstBash); scenarios that intentionally diverge from bash (sandbox restrictions, blocked commands) are markedskip_assert_against_bash: true.Checklist