Security and AI safety
OxidePM runs your services, so it matters who can tell it what to do. This page explains what an AI agent or an adapter is allowed to do, what gets recorded, and where the protections stop.
The install command installs 0.3.2, the latest published release. The agent socket, audit log, dry runs, policy markers and adapters described on this site are not in that release, and the code that has them is not published yet. These pages describe what is coming. What 0.3.2 has and does not have.
The connection decides who is asking
You talk to the daemon from your shell over daemon.sock. The daemon also binds agent.sock, and every connection on it counts as an AI agent, whatever it claims. The daemon decides from the connection a request arrived on, not from what the client says about itself, and a claim can only make a request stricter, never looser.
An agent that claims to be a person on agent.sock still gets agent limits. This binds an agent that goes through the agent socket or declares itself with OXIDEPM_ACTOR=ai:name. It does not stop a hostile process that runs as the same user and calls oxidepm without declaring anything: code that runs as you is you.
Permission tiers
Every request belongs to one of three tiers: safe, caution or dangerous. A person may make every request. An AI actor is held to the tier.
status, show, describe, logs, ping, hellostop, restart, reloadai_control and not protected, and only when it names the apps (no all, no tags). Written to the audit log before it runs.start (and a config file), delete, flush, kill, save, resurrect, show --revealAn AI actor also has its own rate limits: it can restart the same app once every 10 seconds and five times in ten minutes, so a looping agent can’t keep an app down.
[[apps]]
name = "db"
protected = true # read-only for every non-human actor
[[apps]]
name = "web"
ai_control = true # AI actors may stop, restart and reload it
Protected apps and dry runs
Mark an app protected and an AI actor can’t stop, restart or reload it, whatever ai_control says. It can still read status and logs. A person can still do everything. You change the markers of a running app with oxidepm policy set, without a restart.
Most commands that change something accept --dry-run. The daemon runs the policy as for the real request and answers with a plan: the apps it would reach, in which order, and what it would refuse. It starts, stops and writes nothing. A few commands, such as web, init, env set and check --fix, refuse the flag, and an adapter's own commands may have no rehearsal (E_DRY_RUN_UNSUPPORTED).
$ oxidepm stop all --dry-run ℹ︎ Dry run of 'stop': this is what would happen. Nothing was changed. stop web [step 0] status running stop api [step 1] status running stop db [step 2] status running agent$ oxidepm stop all ✗ ai:assistant may not use 'all' or a tag with 'stop': name the apps Error: ai:assistant may not use 'all' or a tag with 'stop': name the apps
Audit log
Everything an AI or an adapter asks for is recorded, and so is every caution or dangerous request by anyone. A request from an AI that changes something is written to disk before it runs, and refused if it cannot be.
The log is JSON lines in ~/.oxidepm/audit/. Environment values, hook scripts, the arguments themselves and log lines are never written. oxidepm audit reads it, even with the daemon down.
{"v":1,"seq":5,"ts":"2026-10-31T04:21:24.168Z","phase":"decision","req":"r3","client_req":"188ea6-1","actor":{"class":"ai","label":"assistant","via":"agent","pid":1609382,"uid":1001},"op":"restart","tier":"caution","selector":"db","decision":"deny","deny":{"code":"E_PROTECTED","why":"ai:assistant may not restart protected app(s): db. A protected app is read-only for anything but a person"},"dry_run":false}
{"v":1,"seq":6,"ts":"2026-10-31T04:21:24.173Z","phase":"decision","req":"r4","client_req":"188ec7-1","actor":{"class":"ai","label":"assistant","via":"agent","pid":1609415,"uid":1001},"op":"delete","tier":"dangerous","selector":"api","decision":"deny","deny":{"code":"E_POLICY_DENIED","why":"ai:assistant may not make the request 'delete': it is a dangerous request. Ask a person to run it"},"dry_run":false}
{"v":1,"seq":7,"ts":"2026-10-31T04:21:24.177Z","phase":"decision","req":"r5","client_req":"188ee9-1","actor":{"class":"ai","label":"assistant","via":"agent","pid":1609449,"uid":1001},"op":"stop","tier":"caution","selector":"all","decision":"deny","deny":{"code":"E_POLICY_DENIED","why":"ai:assistant may not use 'all' or a tag with 'stop': name the apps"},"dry_run":false}
There is no tamper evidence beyond the file mode: a process with your rights can rewrite these files, as it can rewrite the database.
Adapters and the sandbox
Adapters run as separate programs. Four checks stand between an adapter and your server. None of them is enough on its own.
- 01
Hash check
An archive is imported only if its SHA-256 matches the one you give, or the one in a signed index. The program’s hash is recorded, and an adapter whose executable has changed is not started.
- 02
Consent
Enabling an adapter shows what it asks for, and asks. Nothing runs until you approve. An update that asks for more needs a new approval.
- 03
A grant
What an adapter may ask the daemon to do is limited by the grant you accepted, enforced by the daemon through the same policy, audit log and rate limits as everyone else.
- 04
Sandbox
On Linux, an adapter is started under Landlock (files) and seccomp, limited to what its manifest says. Where the kernel cannot enforce something, the consent screen says so.
What the sandbox does
- Limits which files an adapter can read and write (Landlock).
- Limits which system calls it can make (seccomp).
- Keeps a buggy adapter from wandering into the rest of the system.
What it doesn’t do
- It does not fully contain a hostile adapter. Only install adapters you trust.
- It is a Linux feature. Adapters are started only on Linux, so on macOS there are no adapters and no sandbox.
- It does not block every local socket. Unix sockets such as the session bus, an ssh agent or the display server may stay reachable, and
adapter infolists the ones its self-test could connect to. Newer kernels (Landlock ABI 10, shown asrestricts unix connectinstatus --daemon) can restrict connecting to Unix sockets as well. - It can’t enforce which hosts an adapter connects to. The manifest names them, and the consent screen says “Not enforceable per host”.
- It can’t take back permissions you approved on the consent screen.
Reporting a problem
If you find a security issue in OxidePM or an adapter, please report it privately. Don’t open a public issue.
Report a vulnerability