-
Notifications
You must be signed in to change notification settings - Fork 12.9k
security: harden agent containers (cap-drop, no-new-privileges, pids-limit)#2748
security: harden agent containers (cap-drop, no-new-privileges, pids-limit) #2748boazdori wants to merge 4 commits into
Conversation
Adds migration 016 to introduce security_json TEXT (nullable) to container_configs, threads the column through ContainerConfigRow, ContainerConfig, and configFromDb. No behavior change — consumers arrive in Task 2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
...rConfig Review follow-up to Task 1: the hardcoded INSERT omitted both required columns, silently dropping them on the backfill path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review follow-up to Task 2: use no-new-privileges:true; treat pidsLimit 0/negative as omit (cgroups v2 rejects --pids-limit 0). Adds coverage for pidsLimit:0 and memory:null. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
sturdy4days
commented
Jun 12, 2026
Adopted this on our production fork today (manually ported — our container-runner has diverged — but the securityArgs helper + security_json surface transplanted cleanly). Two independent confirmations worth having on the record: (1) the drive-by createContainerConfig bug is real — our copy had the same truncated column list, and our live rows only had correct cli_scope values because they happened to be set through the update path; any group created through that INSERT silently got the default. Same bug class as #2743's wirings create fix — the silent-ignored named params footgun has now bitten three different INSERT sites. (2) Re-verified Chromium headless rendering under --cap-drop=ALL --security-opt no-new-privileges --pids-limit 2048 on our own image (heavy agent-browser users) — works. +1.
Summary
--cap-drop=ALL,--security-opt no-new-privileges:true, and--pids-limit 2048by default — defense-in-depth so a compromised or escaped container holds fewer Linux capabilities and can't fork-bomb the host.security_jsoncolumn oncontainer_configs(capAdd/memory/pidsLimit/noNewPrivileges) for the rare group that needs a capability back.createContainerConfigwas silently droppingcli_scope(and nowsecurity_json) on the backfill path — the hardcoded INSERT column list omitted those required columns (better-sqlite3 silently ignores unused named params).Why it's safe
SYS_ADMIN, no custom seccomp), so dropping Linux capabilities doesn't break the browser — verified by launching Chromium under--cap-drop=ALL --security-opt no-new-privileges --pids-limit 2048and confirming it renders a page.pidsLimit: 0/ negative is treated as "omit the flag" rather than emitted, because cgroups v2 rejects--pids-limit 0(EINVAL) and would crash the spawn.securityArgs()helper is pure and unit-tested; flags are positioned as validdocker runoptions before the image/entrypoint and don't collide with the credential-proxy args appended later.Test Plan
securityArgsunit tests: safe defaults,capAddoverride,pidsLimitnull/0 omit,memorycap,noNewPrivilegestogglecontainer_configsmigration adds nullablesecurity_json; round-trip test throughcreateContainerConfigpnpm run buildclean; full host test suite greenbuildContainerArgsand the per-group override surface🤖 Generated with Claude Code