Please do not open a public issue for a security vulnerability.
Report it privately via GitHub's "Report a vulnerability" (Security → Advisories → Report a vulnerability) on this repository. If that is unavailable, open a minimal public issue asking for a private contact channel — without details — and a maintainer will follow up.
Please include:
- the version / commit you tested,
- a minimal reproduction (the smaller the better),
- the impact you believe it has, and
- any suggested fix if you have one.
This is a small project; expect an initial acknowledgement on a best-effort basis rather than a guaranteed SLA. Coordinated disclosure is welcome — tell us your intended disclosure timeline and we'll work to it.
DOS is pre-1.0 and ships rolling vX.Y.Z releases from master, with promoted
stable/<codename> tags. Security fixes land on the latest master release first.
Until 1.0, only the most recent release is guaranteed to receive fixes.
DOS exists to be the part of an agent system that does not believe the agents. Its security-relevant value is exactly this adversarial stance toward its own untrusted workers:
verify()adjudicates "did this effect actually happen?" against artifacts (registry / disk / git ancestry) — never from a worker's self-report. A worker claiming success is a request for verification, not a result.refuse(reason_class)makes "I correctly declined to act" a typed, legible, first-class outcome rather than silence or prose.arbitrate()is a pure admission function over leases — admission control on conflicting effects to shared state, unit-testable with no live processes.
This is the same shape the agent-security literature converges on (cognitive/executive separation; the validator that admits effects is structurally separate from the model that proposes them). DOS is intended for authorized use: building safer fleets, defensive verification, security testing of your own systems, research, and CTF/ educational contexts.
A trust substrate is only as good as the boundary it's given. Please understand the limits before relying on DOS:
- DOS is a referee, not a sandbox. It adjudicates and serializes claimed effects; it does not itself confine a malicious process, enforce OS-level isolation, or stop code from doing what its capabilities allow. Pair it with real isolation (containers, VMs, worktrees, least-privilege credentials).
verify()is only as strong as its artifacts. It can adjudicate effects that leave a checkable trace (a file changed, a registry entry, a merge ancestry). It cannot certify the correctness of a judgment that leaves no artifact. Don't read a green verdict as "this was the right thing to do" — only "this provably happened."- The state plane is git-native and operator-visible by design. That is a feature
(auditability), but it means substrate state is not a secret store. Never put
credentials, tokens, or PII into
dos.toml, lane journals,execution-state-style files, or any DOS-tracked state. Secrets belong in a real secrets manager and should be referenced, never stored. - Workspace config is trusted input.
SubstrateConfig/dos.toml(lanes, paths, reasons, stamp grammar) and thedos.renderers/ driver entry points are treated as trusted policy from the workspace operator. Running DOS against a workspace whosedos.tomlor installed entry-point plugins you do not control is equivalent to running untrusted configuration/code — don't. - It's pre-1.0. Interfaces and guarantees can change.
The kernel is deliberately near-stdlib — its only runtime dependency is PyYAML.
The MCP server surface (the [mcp] extra) adds the mcp framework and is the
one place a larger dependency surface is pulled in; it is optional and isolated to the
[mcp] extra. A smaller dependency surface is part of the security posture, not an
accident — please weigh that before proposing new core dependencies.
This project's PyPI distribution name is dos-kernel. The bare dos name
on PyPI belongs to an unrelated package (dos 1.6.0, a Flask/OpenAPI
documentation helper — last released 2020). That package also ships a top-level
dos module, so a pip install dos / dos>=X requirement not only pulls the
wrong project but would shadow import dos. Treat the bare name as a
name-collision/confusion hazard:
- Install / depend on
dos-kernel—pip install dos-kernel,pip install 'dos-kernel[mcp]', or a pin likedos-kernel==X.Y.Z. For local dev,pip install -e .from a checkout. Never depend on the baredosindex name. - The import name is unchanged:
import dos, and the console scripts are stilldos/dos-mcp.[project].name(the dist) and[tool.setuptools.packages.find](the import package) are set independently, so the dist rename leaves the import surface untouched. - The runtime version lookup uses the dist name
(
importlib.metadata.version("dos-kernel")insrc/dos/__init__.py) — looking up"dos"would miss our metadata and could read the squatter's version if it were installed. install.pyis safe by construction — it runspip install -e .against this checkout and then verifies the resolveddos.__file__lives inside the repo (_resolved_dos), so it can never silently pick up the squatter.- A stale
src/dos.egg-info/(from before the rename) re-introduces ados-named dist on the path — delete any*.egg-infocarryingName: dosif you see it.
Everything tracked in this repository is public the moment it is pushed. To keep private material (developer-machine paths, hostnames, personal identifiers) from ever landing here, maintainer clones run a leak scanner over the shippable tree as a local, fail-closed pre-push gate. Two things about it are deliberate:
- The scanner itself is not tracked here. It enumerates the very patterns it
forbids, so committing it would itself be the leak. It is maintained privately
and synced into maintainer clones as an ignored file (see the
scripts/leak_scan.pyentry in.gitignore). - CI cooperates either way. The
leak-scanjob in.github/workflows/ci.ymlruns the scanner when the file is present (a maintainer clone) and skips with a note otherwise — a skipped leak-scan job on a contributor PR or fork is expected behavior, not a misconfiguration.
If you spot what looks like leaked private content in the published tree or its history, please report it through the vulnerability channel at the top of this file rather than opening a public issue.