| Container hardening has no per-app override and read-only root filesystems are opt-in | An image that needs more than the minimal capability set must be granted it host-wide | Default is now enforce: all capabilities dropped except a small documented set, no-new-privileges and a PID limit. APP_CONTAINER_HARDENING_CAP_ADD widens it, warn opts out. Per-app policy is future work |
| Release signing is only as good as its last verification | A broken signing step would go unnoticed until a release | Release workflow signs checksums.txt with cosign and attests provenance; install.sh verifies the signature when cosign is present, and APP_INSTALL_VERIFY=require refuses unsigned releases. The v0.2.0-beta.18 signature was verified with cosign against the documented identity on 2026-10-06 |
The master key is stored in <data dir>/master.key beside the database unless APP_MASTER_KEY is set | A copy of the whole data directory (disk image, host backup, cloud snapshot) decrypts every secret | Open: keep the file out of host backups, or set APP_MASTER_KEY_FILE to a path outside the data directory, or supply it with APP_MASTER_KEY. The default location is unchanged |
| Only apps, databases and models have per-resource IAM. Nodes, projects, domains, registries and settings are ability-gated only | You cannot Deny one node or project to a token that has the ability | Open |
| Git fetches of a private-address Git server are refused by default | A LAN Gitea or GitLab needs APP_GIT_ALLOW_PRIVATE_NETWORKS=true, which relaxes only git fetches | Fixed: git fetches use kit/netguard with their own opt-in. The older shared APP_NOTIFY_ALLOW_PRIVATE_NETWORKS still works for git |
| Bind-mount path checks are lexical | A host symlink inside an allowed directory that points at a protected path is followed by Docker | Open: only operators with root on the host can create such a link |
The session cookie is not Secure over plain HTTP and has no __Host- prefix | The dashboard over HTTP (before a domain and certificate exist) exposes the session to a network attacker | Accepted until HTTPS is enabled; enable it from Settings, Ingress |
| Docker socket is never mounted into apps, but the agent container itself holds it | A compromised agent is root on its node | By design: the agent needs the Engine API. It cannot read other nodes’ env, since the control plane only sends a node the workloads placed on it. The Docker API guard in enforce mode stops the agent’s own client from creating privileged or host-mounting containers, but not code running as root in the agent container |
bindaddr accepts an explicit 0.0.0.0 or :: literal as an interface | Same effect as public, without writing the word | Accepted: an explicit address is an explicit choice |
| The per-app exec opt-out is checked when a terminal opens, not on every re-check | Disabling exec on an app does not end an open terminal | Open |
| AI assistant chat streams are finite per turn and are not re-authorized mid-turn | A revoked caller can finish one in-flight turn | Open |
A pipeline run step, a pre or post deploy hook, a health check exec string and the terminal command all run attacker-chosen shell inside the container by design | Anyone who can edit app.yaml or a pipeline, or hold root, has code execution in that app’s container | By design. Restrict who can push to a deployed branch and who holds write. |
Pipeline steps still splice matrix.*, env.* and secrets.* into script text | These come from the pipeline file or secret store, which is the same trust level as the script | Accepted |
| Pipeline containers share the node’s Docker daemon | A malicious pipeline that reaches the daemon is root on the node | Depends on container hardening above |
| A ClickHouse dump interpolates table names from the target database into SQL | Only a user who already owns the database can craft a name | Accepted, low |
| Sessions are process-local | No session listing across a restart, and no shared sessions for an HA control plane | Accepted for single control plane |
| No SSO or SAML | Sign-in is local password, passkey or OAuth | Open |
| No secret scanning of app source. Image vulnerability scanning is optional and off by default (Supply chain) | Not a boundary Levelrail enforces | Open |