Skip to content

security(control-plane): error leakage, upload limits, WS cap, filename sanitization#96

Merged
ndreno merged 1 commit into
mainfrom
security/control-plane
Jul 2, 2026
Merged

security(control-plane): error leakage, upload limits, WS cap, filename sanitization#96
ndreno merged 1 commit into
mainfrom
security/control-plane

Conversation

@ndreno

@ndreno ndreno commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Area 3 — control plane (#8)

Continues the sequential security work, fail-closed by default.

CP-3 — DB error / schema leakage

Many handlers interpolated the raw sqlx::Error into the response (internal_error_with_detail(format!("...{e}"))), disclosing schema/query internals. All DB call sites now route through the existing generic From<sqlx::Error> mapper (via ?), which logs the detail server-side and returns a generic 500. Input-parse errors (YAML/spec) keep their user-facing detail, since those describe the caller's own input.

CP-4 — unbounded upload buffering

Added explicit DefaultBodyLimit layers: 1 MiB default for JSON endpoints, 32 MiB for the spec/plugin upload routes (POST /specs, POST /projects/{id}/specs, POST /plugins). Bounds how much a caller can make the control plane buffer in memory per request.

CP-6 — WS pre-auth pile-up + filename injection

  • WS session cap: a semaphore in ConnectionManager bounds concurrent WebSocket handlers (registered and pending-registration). Unauthenticated sockets can no longer accumulate during the 30s registration window; excess connections are shed.
  • Filename sanitization: a shared safe_filename reduces an untrusted upload filename to a safe basename — defeating (a) path traversal when the name is joined onto the compile temp dir (worker.rs, a real arbitrary-file-write vector) and (b) CRLF/quote injection when reflected into the spec-download Content-Disposition header. Applied at ingestion (multipart) and defensively at each use. Unit-tested.

Deferred

CP-2 residual (per-project ownership / IDOR): needs the multi-tenant authz model (project-scoped credentials + ownership checks); not exploitable in the current single-admin deployment. Kept tracked in #8.

Verification

cargo fmt --all --check, cargo clippy --workspace --lib --bins --exclude barbacane-test -D warnings, and safe_filename unit tests all green. The new Security Suite CI job (from PR #95) boots the control plane for the authz category, exercising these changes end-to-end.

…me sanitization

Addresses the control-plane hardening items (area 3, issue #8).

- CP-3: DB errors no longer interpolate raw sqlx::Error into responses
  (schema disclosure). All DB call sites route through the existing generic
  `From<sqlx::Error>` mapper, which logs the detail server-side and returns a
  generic 500. Input-parse errors (YAML/spec) keep their user-facing detail.
- CP-4: explicit request-body limits via DefaultBodyLimit — 1 MiB default for
  JSON endpoints, 32 MiB for spec/plugin upload routes — bounding in-memory
  buffering.
- CP-6: cap concurrent WebSocket sessions (semaphore in ConnectionManager) so
  unauthenticated sockets can't pile up during the 30s registration window;
  sanitize upload filenames to a safe basename, defeating path traversal into
  the compile temp dir (worker.rs join) and CRLF/quote injection in the spec
  download Content-Disposition header. Sanitized at ingestion and at each use.

CP-2 residual (per-project ownership / IDOR) is deferred: it needs the
multi-tenant authz model and is not exploitable in the current single-admin
deployment. Left tracked in #8.
@ndreno ndreno merged commit c4c833e into main Jul 2, 2026
13 checks passed
@ndreno ndreno deleted the security/control-plane branch July 2, 2026 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant