Painted Wolf Code (engine codename Lycaon) is a local-first AI coding agent. Its
threat model, trust boundaries, and containment posture are documented in
docs/security.md — read that for the design-level detail behind
this policy.
Please do not open a public issue for a security vulnerability.
Report privately through GitHub's Report a vulnerability flow (repository Security tab → Report a vulnerability), which opens a private advisory visible only to maintainers. Include:
- affected component (Lycaon sidecar, Den frontend, a bundled pack, a dependency, or the paintedwolf.ai website),
- version / commit,
- a description and, where possible, a minimal reproduction,
- the impact you believe it has.
We will acknowledge the report. If we confirm it, we will work toward a fix and coordinate disclosure when one is available. There is no guaranteed timeline.
Security fixes are provided for the latest stable release. Before a stable release
exists, fixes land on the default branch (main).
In scope for a report:
- Local API abuse / IDOR — session hijack, settings or credential mutation, or project-open escape reachable on the loopback HTTP API.
- Path escape — reads or writes outside an approved project root via
.., symlinks, or absolute paths that bypassSandboxBoundary. - Command / argument injection — through verify, scanner, git, or MCP subprocess paths.
- SSRF or egress abuse — outbound web research or
fetch_urlreaching internal / metadata endpoints past theguardedGetand provider-endpoint guards. - Secret exposure — credentials or tokens leaking into logs, tool output, API responses, or transcripts.
- The paintedwolf.ai website — cross-site scripting, unsafe headers or redirects, tampered downloads, or a deployment path an outsider can write to.
Explicitly out of scope for the local-first threat model (see
docs/security.md): multi-tenant hosted auth, per-session
container/microVM isolation, encryption-at-rest for SQLite, and any exposure that only
arises after the bind address is deliberately widened off loopback (which requires TLS +
authenticated clients before it ships).
Some limits of the egress boundary are declared rather than defects, and
docs/security.md § Egress states each one with the test that pins it.
Two come up often: mediation carries TCP only, so UDP reaches the network only under an
approved direct-IP action; and a direct-IP action's declared destinations bound protocol
and port, never the remote host, because Seatbelt accepts no host but * or localhost in
a network address. A report that one of these behaves as documented is not a vulnerability.
A report that one of them can be crossed — UDP leaving under a mediated mode, a narrowed
action speaking an undeclared transport, or the system resolver socket reachable outside
direct IP — is in scope above.
The dividing line for this document is the boundary, not the outcome.
- The agent got outside the permissions it was granted — read or wrote outside an approved project root, escaped its confinement, reached a host it should not have reached, or put a secret somewhere readable: that is in scope above. Private advisory, never a public issue.
- The agent stayed inside those permissions and still did something you did not want — edited a file you did not ask about, made a bad call, ignored instructions, looped: that is not a vulnerability.
- An approved capability did what its approval card said: a command the person let run outside the sandbox, a local service such as a container engine acting through an approved socket, or direct network access reaching a destination the host does not observe. Those are permissions granted, not escapes. A command that runs outside the sandbox, or with any of that reach, without its approval is in scope above.
That second bullet is the only security guarantee here. It is not a promise that every in-bounds mistake is a product defect. You can attach any model, and model output is not deterministic. The host enforces the boundary, injects the prompts, offers the tools, raises the gates, and implements the loop and stall detection it claims. It does not determine the next token.
In-bounds reports belong in a public issue only when you think the host should have
prevented the action, or when a shipped default consistently fails. A single bad judgment
from a model you chose is expected. That bar, and the issue form, live in
REPORTING.md.
If you are unsure which you have, use the private advisory flow.
Reading adversary-controlled content (web pages, MCP tool output, repository files) is
the product, not a vulnerability. The relevant question is whether such content can
drive a consequential action without a human-visible gate. See
docs/security.md § Untrusted content (inbound) for the containment
model and its honest limits before reporting prompt-injection findings.