Skip to content

Security: hoangsnowy/AgentOS.NET

SECURITY.md

Security Policy

Reporting a vulnerability

Please do not open a public issue, discussion or pull request for a security vulnerability. Report it privately through GitHub private vulnerability reporting: the repository's Security tab → Report a vulnerability (direct link). If that is not possible, email the maintainer. We aim to acknowledge reports within a few days and to agree a disclosure date with you once a fix is available.

When reporting, include: affected component, reproduction steps, and impact.

Security documentation

Scope notes

  • LLM keys & secrets are never committed. Set them via dotnet user-secrets, environment variables, or the runtime Settings store (encrypted with ASP.NET Core Data Protection). See docs/SETUP.md.
  • API auth is Keycloak OIDC JWT bearer (RS256); tokens are signed by the Keycloak realm key and validated against its JWKS — rotate the signing key in Keycloak, not in AgentOS.NET.
  • The remote dev-agent runtime executes work on a developer machine — treat the pairing credential as a secret. Remote execution is gated by the RemoteAgent:AutoApprove platform setting, which Production locks off (a gate, not yet a per-run human approval — see the threat model); server-driven shell commands outside the allowlist additionally need approval at the runner console.

Built-in safeguards

  • Tool governance — every tool call goes through IToolGateway → per-tenant policy → evidence log (refusals and errors included). Production enforces a fail-closed allowlist.
  • Build sandbox — generated code is compiled only in an ephemeral, no-network, read-only, non-root container with CPU/memory/PID quotas (ADR-0005); Production locks the sandbox to Container.
  • Prompt-injection fencing — third-party text (tickets, issues, repo content) is wrapped as untrusted data before it reaches a prompt.
  • Operator locks — Production pins the riskiest settings so the Settings UI cannot change them (CONFIG.md); platform-wide settings require the platform-admin role.
  • Audit trail — every settings change (old → new, secrets masked), every direct config write (LLM keys, tokens, prompts, tool policy, budget — recorded as set / cleared, never the value), member lifecycle, invitations and sign-in land in an append-only audit log, viewable in Settings → Audit log and exportable as formula-safe CSV. Platform-scope changes are visible to platform admins only. The application's database role may only add and read audit rows (no update / delete), and each tenant's events form a SHA-256 hash chain that Verify chain checks — it names the first event that was changed or removed.
  • Invitations — single-use, accepted only for the address they were sent to, revocable by a tenant admin until used, and expiring after 1–168 hours (default 24); refused attempts are audited.
  • Tenant isolation — row-level EF query filters and Postgres row-level security on the tenant tables (ADR-0012): every connection runs as a restricted role bound to the caller's tenant, so a forgotten filter returns only the caller's rows, a write for another tenant is refused, and a connection with no tenant sees nothing; the few cross-tenant platform operations run in an explicit, counted platform scope. Outside Development the hosts refuse to start without it. Per-tenant keys are never mixed with another tenant's or the platform's. Cross-tenant endpoints (list / provision tenants) require platform-admin, never the per-tenant admin role; a real-auth E2E proves a second tenant sees none of the first's data.
  • QA gate before every PR — a pipeline result becomes a pull request only when QA passed on real model output (PrGate, enforced inside the PR service itself): failed runs, the iteration cap with QA still failing, and offline canned text are blocked with the reason on the session.
  • Approval policies + repo safety — per tenant / project, an approver (or admin) approves the plan, the pull request, the change and/or the merge on Board › Tasks (audited); a gate fails closed — rejected or nobody who can approve stops the task. AgentOS.NET never opens a pull request from, or merges, the default branch, and refuses a merge the branch's protection would refuse (reviews, CODEOWNERS, required checks, rulesets), also when its token could bypass it. See docs/CONFIG.md.
  • SSRF guard — tenant-supplied hosts are validated and limited to an allowlist.
  • Deny by default — every endpoint needs a signed-in caller unless it is explicitly public (health, sign-in / sign-up, invitation preview, runner download, the self-authenticating runner hub, static files); a test pins the list of public routes. Access tokens are accepted only when signed with RS256.
  • Browser hardening — both hosts send HSTS (outside Development), an enforced Content-Security-Policy (script-src 'self', frame-ancestors 'none'), X-Content-Type-Options: nosniff, X-Frame-Options: DENY and Referrer-Policy: same-origin.
  • Request limits — per-tenant, per-user and per-anonymous-client request rate limits on both hosts (Settings → Platform → Request limits; 429 + Retry-After over the limit).
  • Paired runners — a server-driven shell command runs on a developer's machine only if every segment of the chain starts with an allowlisted build/test/VCS program (REMOTE_AGENT_ALLOW to change); command substitution is refused; anything else needs approval at the runner console and is denied when nobody is there. Each command has a timeout that kills the whole process tree. The runner sends its pairing token in a header, never in the URL (the hub still accepts a legacy query-string form — tracked as a gap).
  • Supply chain / SAST — Dependabot, dependency review, SHA-pinned actions, CodeQL with compiler-enforced twins for its query classes. Release images are cosign-signed (keyless), carry SLSA build provenance and a CycloneDX SBOM attestation, and every release attaches the SBOMs — verify an image before deploying it (docs/RELEASE.md).

Supported versions

This project is pre-1.0. Security fixes land on main and ship as a patch release of the latest minor; the previous minor gets security fixes for 90 days after the next one ships. The full policy (SemVer, prereleases, image tags) is in docs/RELEASE.md.

There aren't any published security advisories