Skip to content

fix(ssh): reject forged sshd process names in the OS entry guard - #94

Merged
LIghtJUNction merged 1 commit into
mainfrom
fix/issue-82-ssh-process-identity
Sep 27, 2026
Merged

LIghtJUNction merged 1 commit into
mainfrom
fix/issue-82-ssh-process-identity

Conversation

@LIghtJUNction

Copy link
Copy Markdown
Member

Refs #82 and #85. This narrowly fixes the SSH adapter's OS-entry guard; it does not close the full CLI/TUI/real-client acceptance issue.

Reproduced defect

An ordinary non-root Python process could set its Linux process name to sshd, spawn the adapter, and pass require_sshd_process(): the old fallback accepted any root-owned executable. A root-owned Python interpreter does not prove an OpenSSH-authenticated session. The same bypass affected sshd-session and sshd-auth names.

Fix

Require a root-owned /proc ancestor with all four UID fields equal to root, continue past unprivileged children to the privileged monitor/listener, and remove executable-ownership fallback. Root application callers remain prohibited. Unreadable/inconsistent process metadata fails closed. No shell commands, accepted operations, credential ceiling, certificate or service configuration is expanded.

Verification

tests/test_ssh_process_identity.py uses real unprivileged Linux processes and PR_SET_NAME for all three spoofed names, plus process metadata/root-caller edge cases. Before the fix: 4 failed / 4 passed. After: 12 passed for this file plus tests/test_ssh_rss.py, including real PostgreSQL identity/revocation and real Git reference transactions. Combined with the separate pending TUI changes, 28 tests passed locally under Python 3.13.5 / PostgreSQL 16.15. Complete Python 3.15 CI must pass independently.

The proc-fixture positive test is not a real sshd deployment acceptance. Full AuthorizedKeysCommand/real sshd, tools isolation and other #82 matrices remain tracked there. No production deployment or administrator SSH configuration changes.

Refs #82 and #85. Only a privileged sshd monitor/listener may establish the OS channel; a root-owned interpreter with a forged comm name is not sufficient. Add real Linux process regressions and preserve root-caller denial.
Copilot AI lite review requested due to automatic review settings September 27, 2026 20:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copy link
Copy Markdown
Member Author

Additional isolated verification on 2026-09-27 UTC: ran an actual OpenSSH 9.6p1 listener on a temporary loopback port with temporary Ed25519 host/client keys and a restricted authorized_keys forced command invoking the changed require_sshd_process() plus parse_command().

Five checks passed: authorized msg call discovery.get {} reached the OS-authenticated entry; shell command sh was rejected; msgd cert issue x was rejected; a different client key was denied authentication; ssh -W forwarding was administratively prohibited. The listener was terminated and temporary key files removed. No production service or global sshd configuration was modified.

This verifies the real OpenSSH process ancestry boundary, not the full application's AuthorizedKeysCommand/database/certificate/clone/push acceptance matrix. The repository's Python 3.15 CI is still a separate merge gate; #82 remains open.

@LIghtJUNction
LIghtJUNction merged commit 5553956 into main Sep 27, 2026
2 checks passed
@github-actions
github-actions Bot deleted the fix/issue-82-ssh-process-identity branch September 28, 2026 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants