No description
Find a file
Claus Lohmar 03a9db03dc fix(security): harden httpx — XFF hops, __Host- cookie, isolation headers
REVIEW-001 (M0) perimeter findings:

- H1: resolveForwarded walked X-Forwarded-For left→right and returned the
  leftmost untrusted entry. An append-style proxy (nginx's default) appends
  the peer it saw to the RIGHT of whatever the client sent, so the leftmost
  entry is attacker-controlled — a fresh rate-limit bucket per request (A3)
  and a forged client_ip in the audit trail (A11/D-031). Walk right→left and
  return the first untrusted entry, falling back to the peer.
- L1s: the session cookie now carries the `__Host-` prefix when it is Secure
  (https), so it is pinned to the exact origin and cannot be shadowed from a
  sibling subdomain. Conditional on purpose: a browser rejects a `__Host-`
  cookie without Secure, which would break the http loopback bootstrap.
- L4s: add Permissions-Policy, Cross-Origin-Opener-Policy and
  Cross-Origin-Resource-Policy.
- Add httpx.IsLoopbackIP: a RESOLVED client IP test that fails closed on an
  empty/unparseable value (the setup-mode gate, H2), sharing a classifier
  with IsLoopbackHost whose "unknown" direction is the opposite, each
  fail-closed for its own decision.

Tests updated: the unit test encoding the vulnerable leftmost expectation is
rewritten, plus right→left/forged-entry/host-classification coverage.
2026-10-14 11:29:52 +00:00
.opencode chore: bootstrap MyDay repository 2026-10-13 11:52:30 +00:00
cmd/myday feat(cmd): add the myday entrypoint 2026-10-14 10:53:57 +00:00
docs/specs docs: add the project plan, M0/M0.1 specs, agent guide and README 2026-10-14 10:53:44 +00:00
internal fix(security): harden httpx — XFF hops, __Host- cookie, isolation headers 2026-10-14 11:29:52 +00:00
.gitignore chore(gitignore): ignore only the root build binary, not the cmd/myday source 2026-10-14 10:53:46 +00:00
AGENT.md docs: add the project plan, M0/M0.1 specs, agent guide and README 2026-10-14 10:53:44 +00:00
config.example.yaml docs: add the project plan, M0/M0.1 specs, agent guide and README 2026-10-14 10:53:44 +00:00
go.mod chore(go): add the Go module manifest 2026-10-14 10:53:46 +00:00
go.sum chore(go): add the Go module manifest 2026-10-14 10:53:46 +00:00
PROJECT_PLAN.md docs: add the project plan, M0/M0.1 specs, agent guide and README 2026-10-14 10:53:44 +00:00
README.md docs: add the project plan, M0/M0.1 specs, agent guide and README 2026-10-14 10:53:44 +00:00

MyDay

A self-hosted employee time, absence & reporting app by Sechpoint. Delivered as a PWA for mobile and desktop. Single-tenant — one company per instance.

Status: 🚧 planning / pre-alpha. No application code yet. The design of record is PROJECT_PLAN.md.


What it will do

Area
Org structure users, the manager hierarchy, departments, positions
Time presence and timesheets (a per-user mode)
Absence leave requests, approvals, balances
Reporting rollups and aggregations

Built as one Go binary: a small core (MyDay.auth — identity, sessions, the door) plus drop-in modules.


Running it

Not yet available — nothing is built. These are the intended steps.

# 1. configure
cp config.example.yaml config.yaml     # then edit; config.yaml is gitignored
# 2. build
go build -o myday ./cmd/myday
# 3. run
./myday

⚠️ First run — do NOT expose it publicly

The first user becomes the top admin (the root of the chain). So the instance bootstraps loopback-only, running a /setup wizard until that admin exists.

# on the server it listens on 127.0.0.1:8080 only (config.example.yaml)
ssh -L 8080:127.0.0.1:8080 user@server        # from your workstation
# then open  http://127.0.0.1:8080/setup  and complete the wizard

Reach the app over localhost / 127.0.0.1 — not a hostname. With an https:// base_url the CSRF and session cookies are marked Secure, so they are not sent over plain http://; and only a loopback origin counts as a trustworthy/secure context for the browser's WebAuthn dialogs. So for first run and any human testing, open the app at http://localhost:8080 or http://127.0.0.1:8080 (via the tunnel above) — never at a bare server hostname.

Only after the top admin exists should you put MyDay behind a reverse proxy and expose it.


Documentation

PROJECT_PLAN.md the plan & decision log of record
AGENT.md instructions for AI agents working here
docs/specs/ implementation specs
config.example.yaml configuration template

Security

  • Secrets live in config.yaml (gitignored) — never commit them.
  • Auth is Passkey (primary) + TOTP (fallback).
  • See PROJECT_PLAN.md §10 for the deferred-security register and its beta gate.

License

TBD.