A decentralized P2P mesh network framework with end-to-end PGP encryption,
blockchain-based event persistence, a fluent Java API, and CXApps: a human-facing application layer where identity, permissions, and logic live on the network.
Built for managed decentralized networks that take security seriously.
Upgrade recommended. This build completes a scoped internal security audit and tightens administrative authorization across the c1 admin handlers, alongside dispatcher and codec work. See CXApp Dispatcher & Security Hardening for details.
ConnectX-0.6.3-20260925.215638-1.jar · published 2026-09-25
Available via the Anvil Development Maven repository. Snapshots are enabled.
Prefer the JAR directly? See the download button above, or browse every published snapshot build in the repository.
buildEvent().toPeer().signData().queue() - signing, routing, and queuing in a single chain. CXS for direct peer delivery, CXN for mesh broadcast. Failed CXS deliveries retry with exponential backoff and promote to CXN after threshold. toNetworkPeer() for explicit CXN routing.
Three-layer signing chain: transport hop signature (NetworkContainer), origin signature preserved through relays (NetworkEvent), and payload signing or E2E encryption (NetworkEvent.d). PGPainless default, fully pluggable via abstract CryptProvider.
Jetty-based bridge punches through firewalls and NAT. No open port required on the connecting side. Bridge health is identity-checked before routing. Supports streamBridgeOnly for proxy-hidden nodes where exposing a direct IP defeats the point.
Per-network blockchain: Admin (c1), Resources (c2), Events (c3). Hybrid consensus with EPOCH/NMI-trust and multi-peer voting for distributed agreement. Append-only - no committed state can be overwritten by any party.
NMI issues Integration Keys to authorize network registration. CXIK binds node identity to network membership at the cryptographic level before participation is permitted. CXIKs can be revoked without disrupting the rest of the network.
CXPlugin / CXMessagePlugin intercept events by service name. Three data levels: raw NetworkEvent, full InputBundle with signed bytes and container, or deserialized typed object via DataLevel.OBJECT. Fully per-instance - multiple independent nodes in the same JVM.
Human-facing app layer over the CX network. Server holds logic; client holds an HTML template. Field values travel over CX and are substituted locally - no raw HTML ever crosses the wire. Two render surfaces: CXNexus (JS disabled, secure) or Chrome extension (JS permitted, scripts bundled at install only). Session-isolated per tab.
Bidirectional encrypted channels via CXStreamPlugin. TCP mux via CXST header on the main P2P port, or WebSocket when an HTTP bridge is confirmed to route to the target. Receiver decides transport via identity-checked health probe. Initiator follows.
MESSAGE payloads must be sent as CXMessage with .signData() or .encrypt(recipientID). Raw unsigned payloads are rejected at the receiver at the protocol level. Cannot be bypassed by a misbehaving peer.
Automatic peer discovery on startup via CXHELLO. Scans ports 49152-49162. Runs once on launch then on configurable backoff (30s / 60s / 10min steady-state). Values configurable via NodeConfig. Zero configuration for local mesh setup.
CXApps extend ConnectX beyond machine-to-machine messaging to serve users directly. A CXAppServer runs on the data-owning node. Fields annotated with @CXAppField and methods with @CXAppMethod are cached via reflection at registration. A CXAppClient runs on the user's local node and holds an HTML template. Field values travel over CX as signed events and are substituted into the template locally. No raw HTML ever crosses the wire. Field values from remote peers are HTML-escaped before substitution, so a compromised peer cannot inject markup or script.
Four operations are supported over the wire: READ (fetch current field values), WRITE (update a field), INVOKE (call a method), REFRESH (re-render with current permissions). All travel as APP_REQUEST / APP_RESPONSE events through the standard NodeMesh pipeline with full signing and verification at every hop. Field and method access is gated per-permission - REFRESH silently omits fields the caller lacks permission to read.
Two render surfaces, one security model. Apps with browserEnabled() returning false are restricted to CXNexus, which renders HTML with JavaScript disabled and runs the node in-process. This surface is for anything touching critical or authenticated data. Apps with browserEnabled() returning true (default) may render in Chrome via the extension. JavaScript is permitted, but scripts may only be loaded from files bundled at install time. Server-provided field values are never executed as script. The developer chooses the surface; the framework enforces the constraint.
Session isolation. Each browser tab receives an independent session token on first load. Multiple tabs for the same app are fully isolated even if they target different server peers. The internal loopback HTTP bridge is bound to 127.0.0.1 only with an additional isLoopback() check as defense-in-depth.
Official CXApps published by Anvil Development are distributed on the CXApps page.
Most P2P frameworks make a choice: either prioritize anonymity, or prioritize developer ergonomics, or provide raw messaging primitives. ConnectX is built around a different requirement: managed organizational networks where administrators need real governance tooling, cryptographic accountability at every layer, auditable state, and a human-facing application surface, without depending on a central server.
libp2p is modular and well-suited for open decentralized systems. It has no built-in permission model, no governance layer, no event persistence, and no application layer. ConnectX adds per-network blockchains, weighted permission entries, NMI provisioning, CXIK-gated registration, and CXApps: a full human-facing application surface that libp2p has no equivalent for.
ZeroMQ is a messaging library: fast, transport-agnostic, no opinions on identity. There is no cryptographic identity, no peer authentication, no routing intelligence, and no application layer. ConnectX is not a messaging library. Every participant has a PGP identity, every message is signed, routing is governed by permission state, and CXApps lets you serve UI directly from node to node.
Tor and I2P are built for anonymity: the threat model is hiding who is talking to whom. ConnectX's threat model is the opposite. Every participant is cryptographically identified, every action is attributable and auditable, and the NMI governance layer assumes you know exactly who is on the network. The two approaches serve fundamentally different use cases.
Matrix federates between homeservers; clients trust their homeserver. ConnectX has no homeserver. Peers communicate directly, the blockchain is distributed across nodes, the NMI can be permanently removed via Zero Trust mode, and CXApps runs application logic on the node itself rather than on a server the user never controls. There is no trusted intermediary to compromise.
ConnectX is not a toolkit or a message bus. It is a complete governed network: PGP identity and cryptographic signing at every layer, weighted permission enforcement, blockchain-backed event persistence, stream sessions, and CXApps for human-facing UI served directly from node to node. Zero Trust mode permanently hands control to the network itself when you are ready.
ConnectX makes cryptographic identity the sole basis for trust at the protocol level. Every message, event, and state transition is signed or encrypted by the originating peer before it touches the wire. This is not defense-in-depth. It is exploit-class elimination.
Traditional exploit vectors like use-after-free, buffer overflows, or data races that corrupt in-memory state cannot escalate into protocol-level attacks. If memory corruption mangles a message in transit, it does not become a privilege escalation. It becomes an invalid signature. The data is either authentically from who it claims to be from, or it gets rejected. There is no middle ground.
The protocol enforces this through a three-layer signature and encryption system: transport-level signing on every hop (NetworkContainer), message-level signing by the original sender (NetworkEvent), and payload-level encryption for application data. Any tampering at any layer breaks the signature chain and the data is dropped.
Security hardening is enforced at every import path. Nodes are not added to the mesh until after all signature checks pass - no provisional state is written to disk before verification. Keys are loaded into a cert cache only and rolled back on failure. Power-loss and file-corruption events generate a scoped recovery file; the affected path is locked from further writes until recovery is confirmed and the file is cleared.
Peer identities are cosigned at provisioning time: a node's identity is attested by the NMI's key, creating a verifiable chain from the network's root to every participant. Peers cannot impersonate each other even on the same network segment. The network remains truly decentralized - cosigning is attestation, not control. The underlying blockchain is append-only; no party, including the NMI, can write over or alter committed state. Every event is permanent once confirmed.
The entire attack surface collapses to one well-understood problem: key compromise. CXNet does not pretend to prevent that. No system can. What it does is eliminate every other path to network-level damage, then gives network owners the governance tools to manage that reality.
For real data networks, there is no way to determine whether an authenticated action was intended or not. If a node's key is compromised and the attacker sends valid signed messages, those are authentic as far as the network is concerned. Same way a stolen badge gets you through a door. The network cannot read minds. What it can guarantee is that nobody gets through the door without a badge, which is the part most systems actually fail at.
The same trust boundary every secure system relies on. CXNet just removes all the other ways to cheat.
ConnectX is built for networks that need real administration without a central server. The Network Master Identity (NMI) provisions nodes, assigns permissions through an embedded permissions framework, and issues Integration Keys (CXIK) to authorize network registration. CXIK binds a node's identity to its network membership at the cryptographic level before the node is permitted to participate. Nodes operate at equal authority within the permission model once admitted.
When the network is ready, the owner can activate Zero Trust mode. This is an irreversible decision that permanently locks the trust structure and removes even the NMI's ability to modify it. The network becomes fully decentralized by design, not by accident.
Networks can operate as open (anyone joins), whitelisted (registration required), or fully private (invitation-only, no public seed distribution). All configuration changes are recorded to the admin blockchain (c1), providing an immutable audit trail of every access policy change.
MESSAGE payloads are sent as CXMessage objects (text + timestamp, serialized as cxJSON1). Raw unsigned payloads are rejected at the receiver at the protocol level. There is no configuration option to disable this; a misbehaving peer cannot bypass it.
Delivery has two modes. Signed messages carry a cryptographic signature tied to the sender's PGP identity, so the recipient can verify exactly who sent it. E2E encrypted messages are encrypted to the recipient's key and signed by the sender. Both paths go through the same five-stage pipeline and produce the same guarantees about origin authenticity.
Plugin sender identity. The CXPlugin interface exposes handleEvent(Object data, String senderCxID) at all three data levels. The sender cxID is resolved from ne.p.oCXID (the origin field, which survives relay) with fallback to the direct container sender. Plugins that only implement the single-arg form are unaffected. CXMessagePlugin.onMessage(String senderID, CXMessage message) delivers both the typed object and the verified origin identity in a single callback.
The network join API lets nodes discover and join non-CXNET networks without NMI-level bootstrap. joinNetworkFromPeers(networkID) sends a SEED_REQUEST to EPOCH first (authoritative), then to all HV peers. Seed.fetchOfficial() tries the peer network first, then falls back to the HTTPS bootstrap file. The public API also exposes getNetworks() and getNetworkIDs() for runtime inspection of a node's current network membership.
A network's definition travels as a cosigned blob: an inner signature by the network's own NMI, wrapped in an outer cosignature from EPOCH. Because both layers verify independently, the blob proves itself. The identity of whichever peer happened to forward it carries no weight, so any peer holding a stored copy can serve a join, the network's own NMI included but not required.
That property is what makes seeding work without a central distributor. A responder attaches its stored cosigned.cxnb to the seed response, and the receiver verifies both signature layers and rejects any blob whose network ID is not the one it asked for before registering anything.
0.6.1 was a trust-chain hardening release. Verification of the inner and outer layers had been sharing a single key set, collapsing the plane separation the two layers exist to provide. In that state EPOCH could sign a seed for any network and have it accepted, and NETEPOCH held enough reach to re-declare itself as an independent network. The layers are now verified separately against their own key sets, with the subject network's backend set checked in depth.
Cosigned blobs also no longer override state already on disk. Historical data is authoritative over new network input, which is what the design always specified; the implementation had been reading identity and network membership out of inbound blobs even for networks it already held.
0.6.2 removed the peer-count vote from the join path. A network previously could not be joined unless three distinct peers answered the seed request, which meant a small network could never be joined at all: the tally sat below threshold indefinitely with no timeout. Since a cosigned blob is self-proving, a verified response is now applied on sight. Consensus is unchanged and still handles every response that fails verification or arrives without a blob. Nothing is trusted that was not trusted before; the vote is skipped only where the signature chain is the stronger guarantee.
EventType has declared ttlMs, maxPayloadBytes and maxRetries for some time, but the retry queue ignored them in favour of a flat 50-attempt ceiling with exponential backoff, so a request could be retransmitted for hours after it stopped being relevant. Retry bundles now resolve their type's real limits once at construction and expire on TTL as well as attempt count. A SEED_REQUEST honours its 60-second TTL and drops in about a minute, letting the join logic issue a fresh one instead of the mesh carrying a stale broadcast.
Upgrade recommended. This 0.6.3-SNAPSHOT build completes a scoped internal security audit (39 files / 7,557 lines) and tightens administrative authorization across the c1 admin handlers, alongside the dispatcher and codec work below. See the download above.
Handler dispatch off the EventProcessor. CXAppServer.handle() previously ran inline on the single mesh thread, so a slow app handler could delay other event processing on the node. CXAppDispatcher adds a bounded pool with one lane per appID: apps run concurrently, while each app's own requests stay ordered. Parsing and app lookup stay on the EventProcessor; only the handler call moved.
Error codes and enumeration defence. Refusal responses have been consolidated to a single FORBIDDEN code rather than distinguishing unknown field, unreadable, unwritable, and denied cases, closing off a way to infer an app's structure by comparing replies. .debug re-opens detail without granting access.
Field value encoding. stringify used String.valueOf while coerce read cxJSON1, so a Map went out as {a=b} and came back as an unparseable success. The client had no cxJSON1 branch at all and silently applied null. Both are fixed and consolidated into CXAppCodec so they cannot drift apart again.
In-process calling API. CXApps could previously only be reached from a browser. ConnectX.sendAppRequest plus read/write/invoke/refresh now return CompletableFuture, completed on a dispatcher lane so caller callbacks never land on the EventProcessor. ttlMs added to both annotations.
Inherited members and arity. buildCache only saw the concrete class, so a shared base app's members were missed. It now walks the class hierarchy. INVOKE requires exact arity instead of null-padding.
APP_RESPONSE handling is now guarded on sid + app + origin before it can update client state.doAfter that could produce contradictory outcomes.assert-based null check with a real runtime check, since asserts are disabled by default.escapeHtml is now context-aware, closing an attribute-injection gap.us.anvildevelopment. allowlist wildcard alongside its narrower entries.Also corrected: registerPeerHint now writes as intended (a validation check had been silently blocking it); confirmed escapeAttr correctly escapes quotes.
The six c1 admin handlers (GRANT_PERMISSION, BLOCK_NODE, UNBLOCK_NODE, REGISTER_NODE, and related paths) now go through an explicit authorization check before applying changes, closing a gap where these actions could previously be processed without one.
CXNetwork.checkAdministrativeAuthority now requires the target network's NMI, backend set, or the action's permission - never CXNET's. Zero Trust activation fully demotes the NMI. Permission already declared BlockNode/UnblockNode/RegisterNode, and enforcement is now wired up to match.
All six handlers now authorize strictly on verified origin (oCXID), removing a transmitter-based fallback that didn't require direct authorship of the event. ZERO_TRUST_ACTIVATION - an irreversible operation - now checks the correct authority field.
Verification. 43/43 tests across 3 CXApp classes, build succeeded. Bootstrap run clean (covers the Jackson allowlist narrowing, seed consensus, IOThread). Docs: CX-PROTOCOL.md CXApps section rewritten; CHANGELOG has 7 new sections.
CXStreamPlugin provides full bidirectional stream sessions between peers. Open a session with openStream(targetCxID, localHost), accept with acceptStream(session), write with session.write(data), and close with session.close(cx). Sessions run over the same cryptographic pipeline as all other ConnectX traffic.
Transport is negotiated automatically. TCP mux is the default: stream frames are multiplexed on the existing P2P port via a CXST header, so no additional port is needed. When both peers have a working HTTP bridge, the receiver probes its own health endpoint and verifies the response identity matches its own node ID before advertising WebSocket. If the external URL routes to a different server, it falls back to TCP. The initiator follows whatever transport the receiver advertises in ACCEPT. NodeConfig.streamBridgeOnly = true disables TCP for nodes behind reverse proxies where exposing a direct IP defeats the point.
ConnectX distributes I/O and cryptographic work across five dedicated stages. Ingress and egress each run independent thread pools so neither direction can stall the other. State transitions are serialized through a single-threaded processor. No locks required for correctness.
CPU-heavy cryptographic operations scale across cores in stages 2 and 4. The single EventProcessor in stage 3 guarantees atomic state without synchronization overhead. No single slow operation blocks a parallel path.
Baseline report from 2026-03-24. Coverage has grown since - stream sessions, CXApps (19 unit tests), CXIK, and a full JUnit 5 MultiPeerTest suite (E2E encryption, permission enforcement, spoofed-sender rejection, signed/unsigned delivery) were all added after this snapshot. Core networking, cryptography, and threading paths are fully exercised. Subsystems not yet implemented are at 0% by design.
| Package | Class | Method | Line | Notes |
|---|---|---|---|---|
| network.threads | 100% | 100% | 80% | Full pipeline thread coverage |
| network.events | 92% | 83% | 87% | All typed event classes exercised |
| network.nodemesh | 92% | 72% | 57% | Core mesh, peer directory, retry logic |
| crypt.pgpainless | 100% | 83% | 62% | Sign, verify, encrypt paths covered |
| network (core) | 75% | 50% | 48% | CXNetwork, InputBundle, CXPath |
| io | 83% | 56% | 47% | Serialization and I/O paths |
| us.anvildevelopment.cxnet | 80% | 50% | 54% | ConnectX API, EventBuilder |
| app | 0% | 0% | 0% | CXApps - added after this snapshot |
| analytics | 0% | 0% | 0% | Not yet tested |
| api | 0% | 0% | 0% | Plugin interfaces, exercised indirectly |
| network.remotedirectory | 0% | 0% | 0% | Not implemented |