Security
Security
XORCISE runs offensive agents against deliberately vulnerable targets on your own machine. That deserves a page that says how the isolation is built, what crosses the boundary, how to tell us when it is wrong, and what we have not done yet.
Reporting a vulnerability
Email security@xorcise.ai. Please include the XORCISE version (xorcise --version), the host platform, what you did, what you expected, and what happened instead. A proof of concept helps more than a description of one.
We ask for coordinated disclosure: give us a chance to ship a fix before you publish, and we will credit you in the release notes unless you would rather we did not. We do not run a bug bounty, and we will not threaten anyone who reports a finding in good faith.
If you would rather not send it in the clear, encrypt to our disclosure key. Verify the fingerprint against this page before you trust it. We serve both from the same host, so this checks that you have the right key, not that nobody replaced it.
7669 9A0C 221D D2F8 4358 E871 FC6A E63E B8E3 EB95curl -sSL https://xorcise.ai/security/xorcise-security.asc | gpg --import.Still not published: a response-time commitment and a security advisory feed. Report anything you find in the meantime. The absence of a process is not a reason to sit on a finding.
The isolation boundary
The site says the fence “holds by construction, not by trust”. This is what that means.
Each run mints its own Headscale control plane entry with an ACL scoped to that run: the agent can reach its one mission and nothing else, enforced at the network layer rather than asked of the agent. Rendering a policy that would permit more fails closed: an assert_policy_safe check gates every policy render, and a failed check stops the run instead of widening the fence. The ACL renderer also refuses wildcards outright: a policy containing *:*, a wildcard source or a group grant is rejected before it is ever applied.
Traffic between the agent and the mission is WireGuard, direct peer-to-peer where the network allows it. Where it does not, it falls back to the DERP relay embedded in the control plane, so the control plane can carry run traffic, as encrypted WireGuard packets it cannot read. It is a relay, not a party to the session, but “nothing passes through the control plane” would be the wrong thing to tell you.
Scope analysis over the recorded trace is a complementary audit, not the boundary. If the two ever disagree, the ACL is what actually happened and the trace is what was observed.
The fence confines the agent. It does not harden the mission image you chose to pull, and it is not a substitute for running this on a host you are willing to lose.
What leaves the host
Nothing goes to us by default: no phone-home, no usage telemetry, and the OTel mirror is off. App state, the trace store and every result stay in ~/.xorcise/. Three things do cross the boundary, all of them because you asked for them:
xorcise mission pull and xorcise catalog status reach our registry on demand. Once a mission is on disk, running and grading it never touches us again.:4318. It is the only egress permitted beyond the mission subnet, and it is deliberate.Ports, as shipped locally
| Port | Component | Binds | Detail |
|---|---|---|---|
| :443 | Headscale control plane / rendezvous | published on the host | HTTPS, forwarded to the container's listen_addr on :8443; gRPC on :50443. The only endpoint every peer must reach, and the one that carries the embedded DERP relay. |
| :4318 | OTLP telemetry ingest | loopback + Docker bridge gateway | HTTP, JSON and protobuf, received in-process. This is how the agent's trace arrives, so it binds the Docker bridge gateway alongside loopback by the same rule as the API. |
| :3001 | REST API and the console UI | loopback + Docker bridge gateway | Serves /ui and everything the console does. Unauthenticated, apart from the per-run agent routes. Read it twice: the bridge address is there so the agent container can reach it, which means every local process and every container on that bridge can too. It widens to the IPv4 wildcard on an explicit XORCISE_HOST=0.0.0.0, or on Linux when the bridge gateway cannot be determined at boot. |
| :8800 | Runner plane | 127.0.0.1 | Drives mission containers. The per-run agent-facing routes are authenticated by an HMAC-signed run key that expires at teardown. |
Running it safely
:3001 are unauthenticated, and on a default local install they bind the IPv4 wildcard rather than loopback so the agent container can reach them. Anyone who can route to that port can create runs, read results and browse the host's directory tree through the file picker. Put it behind a firewall, or do not run it on a network you do not control.~/.xorcise/.env and never returned by the API. It is as safe as the machine it sits on./dev/net/tun on Linux for the per-run router. Anything that can talk to your Docker socket can do what Docker can do.Both of those now have a document behind them rather than a sentence: what XORCISE may be pointed at, and where export-control and sanctions responsibility sits, are set out in the acceptable use policy. If your organisation needs a specific export-control classification before it can adopt XORCISE, section 5 says how to ask for one.
Supply chain
Every direct runtime dependency is named with its licence in the third-party notices, including the one we have not been able to resolve.
The playbooks skill you are told to hand to an agent is published from one place, its source repository. We host no archive of it, so there is no second copy to verify against: what you clone is the thing itself, at a commit you can name.
Everything we publish (the engine, the mission library, the playbooks skill and the docs) is Apache-2.0.
What we do not do yet
Published here rather than left to be discovered, because a gap you know about is one you can plan around.
XORCISE is in public beta. Privacy, AI trust & safety, and trademark policies →