Skip to content

feat: harden the hosted content-commit + login paths - #23

Open
euoia wants to merge 1 commit into
mainfrom
feat/auth-commit-hardening
Open

feat: harden the hosted content-commit + login paths#23
euoia wants to merge 1 commit into
mainfrom
feat/auth-commit-hardening

Conversation

@euoia

@euoia euoia commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Phase 3 prep for internet-facing per-site instances (the editor holds a write credential). Implements the small hardening gaps called out in plans/2026-06-25-phase3-auth-hosting.md.

Commit path (server/api/publish.js, git.js)

  • createGitClient now applies hardened git config to every invocation: core.hooksPath=/dev/null, core.fsmonitor=false, disabled LFS smudge/clean/process filters — so staging/committing/checkout of content can't execute arbitrary scripts from a crafted checkout.
  • Commits pass --no-verify (belt-and-braces over hooksPath).
  • New assertNoStagedSymlinks() rejects a staged symlink under the content paths before commit, wired into both commit sites.

Login (server/index.js)

  • Session regeneration on successful login (session-fixation defence — a pre-auth session id no longer carries over).
  • A dedicated stricter limiter on /api/login (10 / 15 min, prod-only; pass-through in dev) on top of the general /api/ limiter.

Verification

  • New tests/git-hardening.test.js: a hostile failing pre-commit hook neither runs nor blocks the commit; a staged symlink is rejected; regular files pass. 3/3 green.
  • auth (5/5) and content-files (10/10) suites still green; changed modules import cleanly.
  • The UI already gates on /api/session (dashboard.js redirects to /login), so no client change was needed.

Phase 3 prep for internet-facing per-site instances (the editor holds a
write credential).

Commit path (server/api/publish.js, git.js):
- createGitClient applies hardened git config to every invocation:
  core.hooksPath=/dev/null, core.fsmonitor=false, and disabled LFS
  smudge/clean/process filters — a content commit can't execute repo
  code from a crafted checkout.
- commits pass --no-verify (belt-and-braces over hooksPath).
- new assertNoStagedSymlinks() rejects a staged symlink under the
  content paths before commit (both commit sites).

Login (server/index.js):
- regenerate the session on successful login (session-fixation defence).
- dedicated stricter limiter on /api/login (10/15min, prod-only;
  pass-through in dev) on top of the general /api/ limiter.

Tests: tests/git-hardening.test.js — a hostile failing pre-commit hook
neither runs nor blocks the commit; a staged symlink is rejected;
regular files pass. auth + content-files suites still green. The UI
already gates on /api/session (dashboard.js redirects to /login), so no
client change was needed.
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