Skip to content

fix(daemon): validate HTTP API bodies and config write paths (H4/H5)#75

Merged
cidrblock merged 5 commits into
mainfrom
AAP-82833
Jul 17, 2026
Merged

fix(daemon): validate HTTP API bodies and config write paths (H4/H5)#75
cidrblock merged 5 commits into
mainfrom
AAP-82833

Conversation

@sudhirverma

@sudhirverma sudhirverma commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes security findings H4/H5: mutating HTTP API routes previously accepted unvalidated req.body, allowing arbitrary config writes, workspace path traversal, field injection, and type confusion.

  • Add Zod request-body schemas for every mutating web route (api-schemas.ts + parseRequestBody), returning 400 on invalid bodies before business logic runs.
  • Allowlist workspace location / workspacePath for config writes; reject .. traversal (400) and non-allowlisted paths (403) with no file write.
  • Share ConfigFile / PolicyConfig schemas in @abbenay/core (config-schema.ts); reuse from the web layer.
  • Use .strict() schemas to reject unexpected fields (field-injection defense).
  • Keep OpenAI /v1 tools passthrough (DR-032): optional tools on chat completions; ConfigFileSchema / ModelConfigSchema accept openai_compat and openai_compat_tools so dashboard/POST /api/config can persist passthrough settings.
  • Document as DR-036; rebase onto main post-#78.

Problem

POST /api/config took location/config with no validation; other routes destructured req.body without schemas. Risk: arbitrary config writes, path traversal, field injection, type confusion.

Changes

Area What
api-schemas.ts Per-endpoint Zod body schemas (config, chat, secrets, provider, policies, sessions, OpenAI /v1, login)
validate-body.ts parseRequestBody, path-traversal check, workspace allowlist helpers
config-schema.ts Shared ConfigFile / PolicyConfig (+ DR-032 openai_compat fields)
server.ts All mutating routes validate before business logic; config writes use allowlist
openai-compat.ts Zod body parse while preserving opt-in tools passthrough
Docs DR-036, CONFIGURATION/CORE/TESTING notes

Test plan

  • Unit: config-schema.test.ts — valid/invalid config, openai_compat accept/reject
  • Unit: validate-body.test.ts — parse failures, allowlist / traversal
  • Integration (web-sse.test.ts):
    • POST /api/config with allowlisted location + valid config → saved
    • location: ../../etc/passwd or outside allowlist → 400/403, no write
    • POST /api/chat with malformed body → 400
  • npm run lint
  • npm test
  • npm run ci:build
  • Manual: dashboard “OpenAI-compatible /v1 tools” save succeeds; /v1 passthrough still works when enabled

Acceptance criteria

Criterion Status
Valid allowlisted POST /api/config saves Covered
Traversal / outside allowlist rejected, no write Covered
Malformed body on mutating routes → 400 Covered
Invalid types rejected before business logic Covered

End-to-end

  1. Authenticated POST /api/config with valid allowlisted location + config → saved.
  2. Same with location: ../../etc/passwd (or outside allowlist) → 400/403, no write.
  3. POST /api/chat with malformed body → 400.

issue: https://redhat.atlassian.net/browse/AAP-82833

@sudhirverma
sudhirverma requested a review from cidrblock July 17, 2026 08:55
@sudhirverma
sudhirverma force-pushed the AAP-82833 branch 2 times, most recently from 2775751 to 249ed89 Compare July 17, 2026 18:12
Add Zod schemas for every mutating web route and allowlist workspace
locations so POST /api/config cannot traverse or write outside known paths.
Move virtual-name validation into config-schema and use importOriginal
in config.js mocks so server import chains no longer break CI.
tsc failed in CI because the barrel re-exported isValidVirtualName
from both config and config-schema after the schema move.
Keep DR-032 passthrough settings persistable via POST /api/config after
Zod .strict() validation (H4/H5).
Avoid .strict() on /v1/chat/completions so DR-020 clients with
stream_options/user/stop keep working. Reject NUL in locations, compare
realpath when present, and validate empty bodies on MCP DELETE routes.
@cidrblock

Copy link
Copy Markdown
Collaborator

Maintainer review fixes in fe156a2 (no follow-up issues — fixed here):

  • OpenAI /v1: drop outer .strict().strip() so common client fields (stream_options, user, stop, …) no longer 400 (DR-020 compat). Required model / messages still validated; optional tools kept for DR-032.
  • Workspace paths: reject NUL bytes; compare realpath when the path exists.
  • MCP DELETE session/remembered routes: EmptyBodySchema like other mutating DELETEs.
  • Tests: OpenAI extras strip; traversal asserts 400; NUL unit case.
  • Docs: DR-036 prose updated (already correctly numbered on branch; PR body had stale DR-033).

Waiting on CI, then approve if green.

@cidrblock cidrblock left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: merge-ready

H4/H5 Zod validation + workspace allowlist is solid. Maintainer follow-up fe156a2 fixes the OpenAI .strict() DR-020 regression (now .strip()), hardens path checks (NUL + realpath), and aligns MCP DELETE body validation.

CI green on fe156a2. Approving.

@cidrblock
cidrblock merged commit e394a64 into main Jul 17, 2026
6 checks passed
@sudhirverma
sudhirverma deleted the AAP-82833 branch July 17, 2026 18:51
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.

2 participants