security: fix bootstrap self-revert and restore three security regressions#142
security: fix bootstrap self-revert and restore three security regressions#142
Conversation
…sions The prompt guard (check_origin_integrity) auto-reverted PR #140's security fixes because it saw origin/main change during the session that merged the PR. This created a circular problem: the guard cannot distinguish `gh pr merge --merge` (legitimate) from a direct push to origin/main (attack). Fix: before reverting, check if snap_hash is an ancestor of current_hash AND the path contains at least one merge commit. Both conditions together are strong evidence of a legitimate PR merge. If true, return 0 without reverting and log an INFO message to stdout only (not the alert file). Also restructured the detection loop to defer alarm printing to the attack path. Previously, "ORIGIN/MAIN MODIFIED" and "ORIGIN/MAIN CHANGED" messages were printed in the detection loop before any analysis, causing false alarms for legitimate PR merges. Three security regressions restored (removed by b2e2fdf): - .nightshift.json in PROMPT_GUARD_FILES (notify_human webhook SSRF) - check_origin_integrity 3-way return codes (0=clean, 1=reverted, 2=failed) - daemon.sh abort-on-revert-failure at both pentest and builder guard points Tests: 1012 passing (+3). Two previously failing tests now pass. New test: test_pr_merge_not_auto_reverted verifies the bootstrap fix.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f6f04c3661
ℹ️ 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".
| if [ "${merge_count:-0}" -gt 0 ]; then | ||
| echo " INFO: origin/main advanced via PR merge -- guard files changed through authorised workflow." | ||
| echo " Changed: ${files_to_restore[*]}" | ||
| echo " Review the merged PR to confirm the changes are intended." | ||
| return 0 |
There was a problem hiding this comment.
Reject direct merge-commit pushes in origin integrity guard
The new PR-merge exemption treats any forward history containing a merge commit as "authorised" and returns success without reverting. That condition is also satisfied by a direct push to origin/main where an attacker locally creates a merge commit (e.g., merge evil into main and push), so guard-file tampering now bypasses check_origin_integrity entirely. This reopens the exact blind-spot the function is meant to block because no PR provenance is actually verified before return 0.
Useful? React with 👍 / 👎.
Summary
check_origin_integritywas auto-reverting legitimate PR merges to guard files because it cannot distinguishgh pr merge --merge(forward merge commit) from a direct push to origin/main (attack)b2e2fdf, which was itself created by the guard incorrectly reverting PR security: fix prompt-guard revert-failure and .nightshift.json SSRF #140Root Cause
PR #140 (session #73) fixed security regressions. The daemon ran
check_origin_integrityafter that session and saw origin/main had changed (because the PR was merged). The function reverted those changes as a "blind spot attack", creatingb2e2fdfand breakingmake check.Fix
Before reverting, check:
snap_hashan ancestor ofcurrent_hash? (forward progression, no force-push)If both are true, return 0. Do not revert. Log INFO to stdout only.
Also moved alarm printing out of the detection loop (deferred to after analysis).
Changes
scripts/lib-agent.sh: ancestor+merge-commit check, deferred alarm printing,.nightshift.jsonin PROMPT_GUARD_FILES, 3-way return codes (0/1/2)scripts/daemon.sh: abort-on-revert-failure at both guard points (exit code 2 handling)tests/test_nightshift.py: 2 previously-failing tests restored + 1 new test for PR merge not revertedTest plan
make checkpasses: 1012 tests, 0 failurestest_revert_failure_returns_exit_code_2passes (was failing before)test_nightshift_json_in_prompt_guard_filespasses (was failing before)test_pr_merge_not_auto_revertedpasses (new test validates the fix)test_detects_push_without_working_tree_change) still passes (rc=1)