security: HIGH-1 authenticated->host-root RCE hardening (+ P5 mutation authz) #7

Open
opened 2026-07-10 22:41:32 +00:00 by kavi · 0 comments
Owner

HIGH-1: authenticated tailnet node -> host-root RCE (from the 2026-07-10 audit)

Full report: ~/audits/kua-deploy-security-audit-20260710.md (SOL-corrected). Not public-exploitable (needs tailnet + accepted identity), but the engine runs as ROOT with docker.sock + root SSH keys + vault token, so any authed-node RCE = full host.

Confirmed sinks: run()=/bin/sh -c (~521); checkout/fetch/build (~783); clone/probe (~566); release (~638); status GET (~1321); rollback/vault (~1200); raw post_deploy (~1072); PUT stores payload (~1491); GET /api/v1/apps→appStatus→shell (~1550).

Fix shape:

  • remove the string-based run() API → executable + argv/cwd (no shell)
  • constrain paths to approved roots (/root/apps); allowlist remotes / repo hosts / vault ids / service names
  • replace post_deploy with NAMED STRUCTURED actions (a safe-char regex around a raw shell hook is NOT enough)
  • validate on LOAD and RELOAD too (~140, ~1463 accept persisted entries without validateEntry) and before execution; inspect the live registry for already-unsafe entries before rollout
  • reject object-special app names (__proto__ etc.)

Policy decision needed: is anything using post_deploy? Only coder-core had it; 0 live registry entries do now → recommend REMOVE outright rather than harden.

Also P5 (same audit): restrict registry MUTATION to an explicit admin capability — today any accepted tailnet node passes the global hook (~69, ~326, ~1489). Interacts with load-time validation.

Worker drafts + tests; HUMAN-in-loop merge; control-plane rollout (P-ROLLOUT). Do NOT auto-deploy.

## HIGH-1: authenticated tailnet node -> host-root RCE (from the 2026-07-10 audit) Full report: `~/audits/kua-deploy-security-audit-20260710.md` (SOL-corrected). Not public-exploitable (needs tailnet + accepted identity), but the engine runs as ROOT with docker.sock + root SSH keys + vault token, so any authed-node RCE = full host. **Confirmed sinks**: `run()`=/bin/sh -c (~521); checkout/fetch/build (~783); clone/probe (~566); release (~638); status GET (~1321); rollback/vault (~1200); raw `post_deploy` (~1072); PUT stores payload (~1491); `GET /api/v1/apps`→appStatus→shell (~1550). **Fix shape**: - remove the string-based `run()` API → executable + argv/cwd (no shell) - constrain paths to approved roots (`/root/apps`); allowlist remotes / repo hosts / vault ids / service names - replace `post_deploy` with NAMED STRUCTURED actions (a safe-char regex around a raw shell hook is NOT enough) - **validate on LOAD and RELOAD too** (~140, ~1463 accept persisted entries without validateEntry) and before execution; inspect the live registry for already-unsafe entries before rollout - reject object-special app names (`__proto__` etc.) **Policy decision needed**: is anything using `post_deploy`? Only coder-core had it; 0 live registry entries do now → recommend REMOVE outright rather than harden. Also P5 (same audit): restrict registry MUTATION to an explicit admin capability — today any accepted tailnet node passes the global hook (~69, ~326, ~1489). Interacts with load-time validation. Worker drafts + tests; HUMAN-in-loop merge; control-plane rollout (P-ROLLOUT). Do NOT auto-deploy.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kavi/kua-deploy#7
No description provided.