Living Document Notice
Published 2026-10-29. The evolving architecture, revisions, and connected notes for this dispatch live in the Stax Digital Garden.
Local IPC Over Unix Domain Sockets
Summary
Binding inter-process communication services to local TCP ports creates unnecessary attack surface on user workstations. Malicious websites executing in modern browsers can probe localhost ports, execute DNS rebinding attacks, and issue unauthorized cross-origin requests to internal tools. The Tender daemon enforces bidirectional local IPC using Unix domain sockets on POSIX platforms and named pipes on Windows.
Filesystem access controls and operating system security descriptors replace network authentication protocols. By verifying peer user credentials directly at the kernel boundary, the daemon prevents unauthorized processes from reading note contents or altering synchronization state.
The Vulnerability of Localhost TCP
Many developer tools communicate between client UIs and background daemons using HTTP or WebSockets over 127.0.0.1. While convenient, binding to the local network stack introduces distinct security risks:
- Cross-Site Probing: Web pages running JavaScript in a browser can scan 127.0.0.1 across common port ranges, fingerprinting installed developer software.
- DNS Rebinding: Attackers can configure external DNS records that resolve first to an attacker-controlled server and subsequently to 127.0.0.1, bypassing same-origin browser policies.
- Port Collisions: Hardcoded port numbers prevent multiple users or multiple isolated vault instances from executing concurrently on the same machine.
Network firewalls rarely filter localhost traffic. Once a service listens on 127.0.0.1, any non-sandboxed process running on the operating system can connect to that port.
+-------------------------------------------------------------------+
| IPC Security Matrix |
| |
| Browser Sandbox Native Desktop Application |
| +---------------+ +------------------------------+ |
| | Arbitrary JS | | Obsidian / CLI / Client | |
| +-------+-------+ +--------------+---------------+ |
| | | |
| | TCP 127.0.0.1:8080 | AF_UNIX / Pipe |
| | (BLOCKED BY TENDER) | (0600 Permissions)|
| v v |
| +---------------+ +------------------------------+ |
| | Network Stack | | Kernel VFS Security Layer | |
| +---------------+ +--------------+---------------+ |
| | |
| v |
| +------------------------------+ |
| | Tender Daemon | |
| +------------------------------+ |
+-------------------------------------------------------------------+
Unix Domain Sockets on Linux and macOS
On Linux and macOS, the Tender daemon establishes its control interface using Unix domain stream sockets (AF_UNIX). The socket file resides within the user-specific runtime directory:
- Linux:
/run/user/<UID>/bosun-pkm/tender.sock - macOS:
~/Library/Application Support/bosun-pkm/tender.sock
The daemon sets filesystem permissions to 0600 (S_IRUSR | S_IWUSR) immediately upon binding. This prevents any other user account on a shared system from opening the socket file.
The server inspects peer credentials on every connection before processing incoming frames:
use std::os::unix::net::UnixListener;
use nix::sys::socket::{getsockopt, sockopt::PeerCredentials};
fn verify_client(stream: &std::os::unix::net::UnixStream) -> Result<(), std::io::Error> {
use std::os::unix::io::AsRawFd;
let creds = getsockopt(stream.as_raw_fd(), PeerCredentials)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::PermissionDenied, e))?;
let current_uid = nix::unistd::getuid();
if creds.uid() != current_uid.as_raw() {
return Err(std::io::Error::new(
std::io::ErrorKind::PermissionDenied,
"UID mismatch on IPC connection",
));
}
Ok(())
}If the connecting process UID differs from the daemon process UID, the daemon closes the connection immediately.
Windows Named Pipes Implementation
On Windows platforms, Unix domain sockets have limited support across older runtime environments. The Tender daemon provides equivalent isolation using Windows Named Pipes (\\.\pipe\bosun-tender-<USER_SID>).
The daemon constructs a strict Security Descriptor containing a single Discretionary Access Control List (DACL):
SECURITY_ATTRIBUTES sa;
TCHAR *szSddl = TEXT("D:(A;;GA;;;PS)(A;;GA;;;OW)"); // Owner and Process Self only
ConvertStringSecurityDescriptorToSecurityDescriptor(
szSddl,
SDDL_REVISION_1,
&(sa.lpSecurityDescriptor),
NULL
);
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = FALSE;
HANDLE hPipe = CreateNamedPipe(
"\\.\pipe\bosun-tender-session",
PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1, // Max instances
65536, // Out buffer size
65536, // In buffer size
0, // Default timeout
&sa
);The pipe definition restricts access strictly to the owner security identifier (OW). Web browsers and unprivileged sandboxed programs cannot obtain a handle to the pipe, blocking unauthorized access at the Windows kernel object manager level.
The wire protocol on top of both transports uses length-prefixed binary frames:
[ Frame Length: 4 Bytes (Big-Endian uint32) ] [ Message Body: Protobuf / FlatBuffers ]
When a frame length exceeds the 16MB buffer threshold, the socket drops the connection with an ERANGE error code, preventing heap memory exhaustion attacks.
- Directus Target: tender
- Garden Source Reference: Local IPC Standards, Unix Domain Sockets, Named Pipes Transport, MOC - Ingestion & Capture, MOC - Local-First Systems and Synchronization, MOC - Bosun PKM Tools