This document describes the AinoWork trust model, names the security boundaries the project treats as load-bearing, and defines the scope for vulnerability reports.
Report privately via GitHub Security Advisories or oinone@shushi.pro. Do not open public issues for security vulnerabilities.
A useful report includes:
- A concise description and severity assessment.
- The affected component, identified by file path and line range
(e.g.
backend/app/modules/auth/router.py:115-140). - Environment details (AinoWork version, commit SHA, OS, Docker version).
- A reproduction against
masteror the latest release. - A statement of which trust boundary in §2 is crossed.
Please read §2 and §3 before submitting.
AinoWork is a self-hosted, multi-tenant collaborative platform. Its posture is layered, and the layers are not equally load-bearing.
- Host machine. The physical or virtual server running the Docker Compose stack — backend, frontend, PostgreSQL, Redis, and sandbox containers.
- Sandbox container. An ephemeral Docker container spawned per AI agent session. Runs user-provided code, shell commands, and browser sessions.
- Trust envelope. The set of resources an operator has implicitly granted AinoWork access to by deploying it: the Docker socket, the host network, the configured data volumes, and any credentials in the environment file.
- External surface. Any channel through which a caller outside the Docker network can reach AinoWork: HTTPS (port 3000), the terminal WebSocket, the SSE event stream, and the browser VNC WebSocket.
The only security boundary against adversarial LLM output is the Docker sandbox container. Nothing inside the application process — not RBAC, not the Fernet body-encryption layer, not the middleware chain — constitutes containment of LLM-emitted code.
AinoWork supports one supported production isolation posture:
- Docker sandbox mode (
SANDBOX_MODE=docker): Each agent session spawns an ephemeral container on an isolated bridge network. The container has no access to the host filesystem beyond its workspace volume. Shell, file, and browser tools operate inside this container. Resource limits (CPU, memory) are configurable.
Operators running with SANDBOX_MODE=host or exposing the Docker
socket to containers beyond the socat proxy are operating outside the
supported security posture.
- Access tokens are JWTs signed with RSA-256. They are stored in browser memory only (never localStorage / sessionStorage) to prevent XSS theft.
- Refresh tokens are managed via
httpOnly,Secure,SameSite=Strictcookies. The backend rotates them on each use and detects reuse. - Password hashing uses Argon2id with per-user salts.
- Body encryption uses Fernet (AES-128-CBC + HMAC) for sensitive request payloads. The encryption key is derived via SHA-256 from the configured secret.
The following components screen or warn about behavior. They are useful. They are not boundaries.
- RBAC permission checks — Enforced server-side on every API endpoint. A convenience, not a sandbox. An authorized user with terminal access can still execute arbitrary code within their sandbox.
- SSRF protection —
SsrfSafeTransportblocks HTTP requests to private/reserved IP ranges from the backend. It is a network egress guard, not a containment mechanism. - API rate limiting — Protects against abuse but does not prevent an authenticated user from exhausting their own sandbox resources.
| Surface | Protocol | Boundary |
|---|---|---|
| Frontend (port 3000) | HTTPS | Network — reverse proxy with TLS termination |
| SSE event stream | HTTPS (long-poll fallback) | Network — same origin |
| Terminal WebSocket | WSS | Network — token-authenticated |
| Browser VNC WebSocket | WSS | Network — token-authenticated |
Uniform rule: Authorization is required at every surface. The frontend SSO and API layers enforce this. The terminal and browser WebSocket endpoints validate the access token before upgrading the connection. Unauthenticated access to any surface is a code bug in scope under §3.1.
- Escape from Docker sandbox isolation: an attacker-controlled code path reaching host state that the sandbox claimed to confine.
- Unauthorized access: a caller without valid credentials reaching any API endpoint, WebSocket, or SSE stream that requires authentication.
- Credential exfiltration: leakage of operator credentials, access tokens, refresh tokens, or API keys to a destination outside the trust envelope.
- Trust-model documentation violations: code behaving contrary to what this policy or AinoWork's own documentation predicts — including cases where AinoWork has documented a stance about how its output should be rendered and a code path breaks that stance.
"Out of scope" means "not a security vulnerability under this policy." Improvements are still welcome as regular issues or pull requests.
- Bypasses of in-process heuristics (§2.4) — RBAC check edge cases on non-sensitive endpoints, rate-limit bypasses, and pattern mismatches in SSRF filtering. These components are not boundaries.
- Prompt injection per se. Getting the LLM to emit unusual output is not itself a vulnerability. "I achieved prompt injection" without a chained §3.1 outcome (sandbox escape, credential leak, or unauthorized access) is not an actionable report.
- Consequences of running in host mode. Host-mode sandboxing
(
SANDBOX_MODE=host) is a documented break-glass setting. Code execution reaching host state under this mode is expected. - Default credentials in the starter
.env. The starter ships with well-known defaults (admin@ainowork.dev/admin123456) for first-run convenience. Operators are expected to change them before production use. This is documented in the Quick Start. - Self-signed certificates. The starter generates self-signed certificates for local HTTPS. Operators are expected to replace them with CA-signed certificates for production.
- Third-party skills and community contributions. Skills installed from the marketplace execute arbitrary code inside the sandbox — that is their documented behavior. Operator review before install is the boundary.
- Run in Docker sandbox mode (
SANDBOX_MODE=docker). Never use host mode in production. - Replace the default RSA keys in
ainowork-starter/keys/before deploying. The shipped keys are for testing only. - Change the default admin password immediately after first login.
- Replace self-signed certificates with CA-signed certificates.
- Do not expose port 3000 directly to the public internet without a reverse proxy, VPN, or firewall.
- Rotate the
BODY_ENCRYPTION_SECRETperiodically. - Keep Docker images up to date (
:latesttag).
- Coordinated disclosure window: 90 days from report, or until a fix is released, whichever comes first.
- Channel: the GitHub Security Advisory thread or email correspondence with oinone@shushi.pro.
- Credit: reporters are credited in release notes unless anonymity is requested.