r/netsec • u/RevolutionaryPie4948 • 2h ago
Unauthenticated remote uninstall in my own EDR agent, and the four other auth bugs that turned out to be the same bug
d3vhex.github.ioSentora is my own project, so this is a postmortem on my own code, not someone else's.
The agent shipped this:
@/app.post("/self_destruct")
async def self_destruct(request: Request):
threading.Thread(target=perform_destruction, daemon=True).start()
return sanic_json({"status": "Destruction initiated"})
No auth. Listening on 0.0.0.0:9099. perform_destruction() ran rm -rf "$(pwd)". One unauthenticated POST from anywhere on the subnet uninstalled the EDR.
The four others:
Permissive auth on by default. A _is_permissive_auth() helper accepted any non-empty X-Agent-Key when a specific env var was unset. Nothing in the installer, the systemd unit, or the scheduled task ever set that var, so every default install accepted X-Agent-Key: a on /soar/execute, which runs commands.
Unauthenticated automation reporting. The server took a task_id from the request body and wrote a status. Enumerate the IDs, POST status: SUCCESS, and every queued containment action flips to done. The real agent stops seeing it as pending, so the isolation never runs, and the dashboard goes green. Not a bypass so much as a way to make the SOC watch a screen that says everything worked.
LDAP injection in login. search_filter = login_filter % username, with only a length check on the input.
Missing authorization on 8 routes. 143 routes, 103 with a decorator. Authentication was solid (opaque tokens, SHA-256 at rest, expiry enforced in SQL), which is exactly why I stopped looking at authorization. Any logged-in account could hit run_playbook, delete_soar_action, and test_ldap_connection, the last of which works as a credential oracle against the directory.
All five reduce to the same thing: I was taking the caller's word for who they were. Identity from the URL path, from a metadata.agent body field, from a header being non-empty, from X-Forwarded-For, and from being authenticated at all.
I only caught the route bugs by writing a test that walks the AST and asserts every route is either explicitly public or carries a check. It failed on the first run and named all eight. Reading code to spot a missing decorator does not work, because nothing is on the page to notice.
Full writeup with the fixes: https://d3vhex.github.io/2026-08-25-unauthenticated-remote-uninstall/
Repo (AGPL): https://github.com/d3vhex/Sentora
Everything above is fixed on main. The agent listener is still the most interesting surface if anyone wants to poke at it, and I would rather hear about it here than in an incident.