aerolite is pre-1.0 and not hardened for untrusted networks. Please read the exposure section below before you deploy it anywhere reachable.
Report privately through GitHub's private vulnerability reporting: Security → Report a vulnerability.
Please don't open a public issue for anything exploitable. Include what you
did, what happened, and the commit you tested — a curl or short script is
worth more than a description.
Expect a first response within a week. There is no bounty; this is a solo-maintained project.
Only main is supported. There are no backports.
These are not vulnerabilities to report. They are the current design, and they are documented here so nobody discovers them the hard way in production.
The core registers builtin methods that any caller may invoke, over DDP
(/websocket) or plain HTTP (POST /rpc), with no credentials:
collection.list collection.find collection.docs
collection.insert collection.update collection.remove
collection.ensureIndex
durable.call
workflow.start workflow.remove workflow.status workflow.list
So anyone who can reach the port can enumerate your collections, read every
document in them, write and delete documents, invoke durable-object methods,
and start or delete workflow runs — including internal collections such as
_workflowRuns.
Three specific misconceptions worth naming:
- Publications do not protect your data. They gate subscriptions. A
client that skips
suband callscollection.findreads the underlying documents regardless of how the publication filters or projects them. - This is not Meteor's
insecurepackage. That one can be removed, and allow/deny rules put in its place. aerolite has no equivalent hook yet. - You cannot write the authorization yourself, either. See below — the request path carries no caller identity, so a handler cannot tell who is calling it.
This is the structural gap behind everything above, and it is easy to miss:
pub async fn dispatch_method(&self, method: &str, params: Vec<Value>) -> Result<Value, Error>Method handlers are Fn(Arc<Server>, Vec<Value>). Publication handlers are
Fn(Arc<Server>, Vec<Value>). Server plus params — no caller identity is
passed to either. The DDP session has an id, but it is used for log lines
and never reaches dispatch.
Two consequences:
- An identity system alone would not close the data plane. There is nowhere in a handler to consult "who is calling", so authentication without the plumbing below buys you nothing.
- Per-user publications are not possible today. In Meteor, scoping data to
the caller is
Meteor.publish('myDocs', function () { return Docs.find({owner: this.userId}) }), wherethis.userIdis server-trusted. An aerolite publication sees onlyparams, which the client supplies — so a client subscribing with someone else's id receives that user's documents. There is currently no way to write a correct per-user publication, however careful the app author is.
| Endpoint | Exposure |
|---|---|
GET /logs |
In-memory log buffer: method names, errors, and any values your app puts in log fields |
GET /stats |
Collection names and document counts, workflow run counts, process metrics |
POST /raft/vote, POST /raft/append, GET /raft/status |
Inter-node consensus. A caller who can reach these can inject Raft RPCs |
POST /cluster/method |
Method forwarding to the leader |
/worker is the exception: it is locked to a token minted per run under
aerolite run, and to AEROLITE_WORKER_TOKEN under --no-worker when set.
No request-body or WebSocket message size limit is configured, so a single large frame can drive allocation on the server.
- Keep the default loopback bind.
127.0.0.1:3000is currently the main thing between a node and the open internet. - Put an authenticating reverse proxy in front of anything public, and let it terminate TLS. aerolite speaks plaintext HTTP/WS.
- Keep
/raft/*and/cluster/*on a private network. Consensus traffic is unauthenticated between nodes. - Don't log secrets.
/logsis readable by anyone who reaches the port. - Treat the data as world-writable until an authorization layer exists.
"Add auth" is not one feature here; it is a prerequisite refactor and then a feature, in this order:
- Thread a caller context through the request path — session →
dispatch_method→ handler, and the same for publications. This is the load-bearing step and a breaking SDK change:app.method((ctx, ...args) => …)and publications that can readctxinstead of trusting client params. Nothing else can be built correctly until this exists. - Consult that context in the builtin methods, and give apps a way to disable the builtin collection writes outright so they can expose only their own methods.
- Then an identity system — accounts, sessions, tokens — becomes an ordinary feature on top, rather than something with nowhere to plug in.
Until at least (1) and (2) land, aerolite is best treated as a development and trusted-network system, and no amount of care in application code can make a publicly-bound node safe.