Repository navigation
Conversation
lzfxxx
marked this pull request as ready for review
October 13, 2026 01:00
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix native ChaCha20-Poly1305 nonce corruption during nested writes
Target repository: mscdex/ssh2. Draft for upstream review.
Baseline tested: ssh2 1.17.0, Node 22.20.0, macOS, optional native binding absent.
Updated 2026-10-12: master HEAD a3a39d7
still contains the pattern. GitHub connector reads verified the SHA and searched
open/closed issues and PRs. No equivalent fix was found within the documented
search coverage; see upstream-search.md for limits. Highest tag is v1.17.0;
GitHub Releases is empty, and npm registry publication state was not checked.
Summary
ChaChaPolyCipherNative.encrypt(packet) + allocate a nonce buffer scoped to this invocation encrypt packet length invoke onWrite(length) encrypt payload using the same invocation's nonceThe native implementation uses a module-scoped mutable nonce buffer.
The synchronous onWrite callback can encrypt through another cipher, as
in nested SSH forwarding. That nested call changes the shared sequence
number before the original cipher encrypts its payload. The packet length
is valid, but the peer decrypts an invalid payload.
Use a zero-initialized 16-byte buffer scoped to encrypt(). This isolates
the nonce across different cipher instances in nested callbacks without
changing cipher negotiation or SSH access policy.
Evidence
nested service-request payload validation; regression exits 1.
regression exits 0.
The integrated test/test-protocol-chacha-reentrancy.js forces the native
cipher and decipher, validates authenticated decryption and exact payload,
and covers standalone/nested writes at sequence numbers 0, 3 and 0xFFFFFFFF.
It fails on unpatched HEAD and passes all six cases with the patch.
node test/test.jsentry point was rerun on2026-10-13 using Node 22.20.0 on macOS with normal approval for localhost
and test sockets. It exited 1: 12 test files passed, including the native
six-case regression and upstream crypto; three failed. The OpenSSH 10.3 RSA
integration test reported client exit 255; server-hostkeys and SFTP tests
reported localhost AggregateError ETIMEDOUT. These failures have not been
diagnosed or confirmed against an unpatched baseline in this execution.
One unsupported OpenSSL cipher case was skipped. This PR does not claim
the full suite passes.
patching. Existing local dependencies were copied; no software was installed.
Compiled optional binding and Windows/Linux were not tested. Lint was not run
because ESLint and the upstream config package are unavailable locally.
Merge Danger
Door: two-way. Revert the invocation-local allocation to undo the change.
Blast Radius: cryptography.
One small buffer allocation per packet on this native path. Benchmarking and
upstream review are appropriate. Optional compiled binding and other ciphers
are unchanged. This does not claim to make same-instance recursive encryption
or all module-scoped scratch storage generally reentrant.