Reviewed on 2026-09-08: the shipped C programs, node-key gate, vendored SDK helper use, Dockerfile, shell scripts and CI workflow. Host implementations were consulted to check API contracts. This is a source and regression-test review, not a proof of absence of vulnerabilities or a comprehensive audit of Synchronicity, russh, LLVM, Docker or their dependencies.
- SSH parsing: C-string comparison accepted
sftpfollowed by an embedded NUL and extra bytes as the exact subsystem name. Comparisons now use the full JSON string length and bytes. The node-key gate still applied before this request; this was not a node-authentication bypass. - SSH resource cleanup: closing a session before selecting its backend retained the connection's only session slot. Receive EOF is now watched before a shell or SFTP service starts, releasing the channel and any PTY. Exploitation required an authorized node and affected its own connection.
- Artifact integrity: a shared mutable image tag could be replaced by another build before extraction. Extraction now uses the exact immutable image ID returned by this build, with registry pulls disabled.
- Test helper filesystem handling: checking existence before copying followed dangling symlinks and left a check/write race. Exclusive creation now refuses existing paths atomically. This affected a local test helper, not the deployed socket runtime.
The CI extraction failure was also fixed: objects live in /artifacts so
Docker's injected root files do not enter the artifact comparison.
./scripts/test.sh covers malformed/mismatched origins and z-base-32 node keys, complete
allowlist validation, immutable artifact selection, stale artifact detection
and dangling-symlink refusal.
./scripts/test-runtime.sh /path/to/synchronicity executes committed BPF objects
against the actual runtime. It covers transport identity despite spoofed
metadata, binary echo under backpressure, permitted shell/SFTP operations,
embedded-NUL subsystem refusal, rejected exec/environment/forwarding requests,
one active session, abandoned-session recovery, and SFTP read/write/delete
traversal attempts. ./scripts/build.sh --check performs a fresh amd64 build
and compares the entire artifact directory byte for byte.
SSH authorization deliberately grants each configured node a shell as the serving daemon's OS account. SSH usernames do not select or authenticate a separate OS account. The SFTP scope does not sandbox that shell. Node-key validation runs before SSH starts; connection metadata never supplies policy.
Runtime admission, authenticated transport, capability enforcement, SFTP path normalization, process cleanup and resource deadlines remain host obligations. Echo and whoami are intentionally available to any caller able to reach their socket. Keep activated script paths, activation configuration, the allowed node's identity and the build host under operator control. Reproducible builds and checksums establish consistency, not the trustworthiness of their source.
allowed_peers accepts up to 16 comma-separated named origins or unpadded
z-base-32 public keys. Parsing validates every entry and the final unused key
encoding bits before granting access. Origin rules compare the authenticated
sy_peer_origin value after normalizing the configured name, and therefore
trust the membership authority to associate that name with a device key.
Hex and the former allowed_node_key setting are not accepted.
allowlist=<tree path> selects a newline-delimited file instead of inline
allowed_peers; configuring both is refused. The server reads one selected
object snapshot in full for each new connection, with limits of 64 KiB,
1,024 peer entries, 1,023 bytes per line and 10 seconds for range reads. Failures
and malformed later lines deny access even after a match. Native tests inject
cold/short reads, timeouts, premature EOF and host errors and check cleanup;
runtime tests cover large files, rejected policy and revocation on a new
connection. File writers are trusted to grant SSH access. Existing sessions
retain their authorization until they end.
The TCP proxy uses the same shared authorization function before opening its
upstream. The shipped manifest permits any TCP port on literal 127.0.0.1;
operator-controlled upstream_port selects one port, with strict decimal/range
validation. Neither upstream selection nor authorization reads caller metadata.
Tests run the committed object against loopback TCP to check denied dials,
invalid configuration, host egress enforcement, backpressure, both half-close
orders and asynchronous connection failure. Local listener clients inherit the
forwarding node's identity and receive the selected service's protocol access.
ssh-session shares the capabilities and request handling of ssh-shell, with
additional absolute-expiry admission and active-session deadline checks. The
bootstrap creates a private device identity locally and prints only its public
key and registration scope/deadline. It neither accepts nor embeds control-plane
credentials and never distributes a device database or private invitation.
An authorized operator registers/revokes the key through the hosted delegation API; the data plane signs the existing delegation record. The socket separately pins the controller's public key. Network admission is not application access, and delegation revocation is not the timer for an existing connection.
The bootstrap checks runtime/program downloads, asks explicit consent before starting, and owns the temporary daemon's normal shutdown and cleanup. See README for clock, direct-process, detached-child and crash-cleanup boundaries. This is authorized remote administration, not sandboxed or exactly-once execution.