Read the Code that Touches Your Content: The Edge Node Agent is Now Public

Neighborhood Nodes
The GitHub page for evolving-edge/edge-node-agent, described as the Evolving Edge edge node Node Core, licensed under the Mozilla Public License 2.0 and marked as a public repository

If you deploy to Evolving Edge, your content is served from machines you don’t own, in buildings you’ll never visit, run by people you’ll never meet. (We know how that sounds.)

When a security team hears it, their first question usually isn’t whether it’s a good idea. It’s something more practical: what does the software on those machines actually do with our content?

Until today, the most honest answer we could give was “read our white paper and take our word for the rest.” That’s a lot to ask of people whose job is not taking anyone’s word for things.

So today we’re giving you something better than our word. You can read the code.

evolving-edge/edge-node-agent is the Node Core of our edge node, published under MPL-2.0. It covers lifecycle management, peer discovery over DHT, WebRTC and tunnel transport, .ee workload caching and serving, and telemetry. In other words, it’s the part that touches your content.

A quick note on how the repo works. We’d genuinely welcome your issues and questions. But the code is published for review, not for contributions: we develop it in our private monorepo and republish it here. That’s a project policy, not a license term. Your rights to the source come from MPL-2.0, not from how we prefer to take patches.


What we left out, and why

A file can be missing for two very different reasons, and blurring them together would be the easy way to mislead you. So here they are separately.

Some of it is proprietary, and it stays that way. We call these Closed Handler Modules, and they’re never exported. There are three:

  • the Level 2 key path, by which a gateway obtains a decryption key from the control plane on a visitor’s behalf
  • inference, Ray and model-cache orchestration
  • node credentials and the release signing keys

In the source tree, each one carries the build constraint //go:build !nodecore. Building with -tags nodecore leaves every one of them out by construction, not by someone remembering to.

One file is held back for a reason we’d rather tell you than hide. updater.go handles the node’s self-update. It isn’t proprietary. It’s missing because the current implementation checks a downloaded binary against a same-origin SHA256 checksum and no cryptographic signature.

Publishing it as it stands would hand someone a precise roadmap for a supply-chain attack: compromise the control-plane host, and every auto-updating node takes whatever binary you give it. And there’d be no upside to offset that, because the weakness is real whether or not the source is public. In this build, self-update is a no-op stub until we fix it.

This is the kind of thing a good security review turns up in week two. We’d rather you hear it from us on day one.

The format isn’t the secret

If you read the core and come away thinking we’re hiding our container format, then we’ve misled you, and we’d rather say so now than let the gap imply it.

The .ee format and its cryptography are already public, by necessity. Level 1 workloads are decrypted in the visitor’s browser, so ee-worker.js - served to every visitor of every Level 1 site - already implements the same key derivation, decryption and decompression. And the ee-builder tool that writes the format ships to every customer. There’s nothing left to conceal there, and the module boundary doesn’t try to.

Where to start reading

If you only have an afternoon, here are four questions reviewers tend to ask, and the files that answer them:

  • What happens to my content on the way to a visitor? ee_handler.go, ee_format.go, content_handler.go
  • What does a node report about the people it serves? analytics.go, heartbeat.go, geoip.go
  • How does a node find and talk to other nodes? dht.go, dht_transport.go, gossip.go, hash_ring.go
  • How does a machine become a node in the first place? enroll.go, device_auth.go, config.go

To build it, run go build -tags nodecore ./.... The tag is required. A plain go build will fail, because the tree deliberately omits files whose stand-ins only compile under that tag.

How each snapshot is made

The public repo has no commit history, by design. Every publish is a single fresh commit, so nothing from the private repo’s past can tag along by accident. For traceability, the README names the monorepo commit each snapshot corresponds to.

Getting a file into the public repo runs through a default-deny allowlist: nothing goes out unless a person has read the file and added it. And the private repo’s CI builds and vets this exact export on every change, so the published tree can’t quietly stop compiling.


What this doesn’t prove

We want to be careful not to oversell this.

Reading the source tells you what the software is written to do. On its own, it doesn’t tell you that the binary on a particular operator’s machine was built from it. That’s a separate problem - signing and verifiable builds - and it’s the same gap that keeps updater.go out of this repo. We’d rather publish the source now with that limit stated plainly than wait until we can claim more.

If you want the full threat model, including what an operator with root on their own machine can and can’t reach, it’s in Two Strangers, One Machine. Chapter 9 pairs each security claim with the test that checks it.

And if you find something we got wrong, we want to hear about it: security@evolvingedge.ai. We aim to acknowledge within one business day.