Files
cgalo5758 ea4fee18b6 Fix five findings from security audit run 2
- Rotate the session token at the OIDC callback and restore the full
  lifetime; cap pre-auth sessions at 15 minutes and write no session
  for bare anonymous requests
- Treat db-dsn as a secret: accept db-dsn-file, log only host, port,
  database and user, and never echo a malformed DSN in an error
- Guard the logout callback with a state cookie so a forged visit
  cannot end a live session
- Collapse FedWiki site actions on a foreign tenant's domain to the
  not-found answer, as for a domain that does not exist
2026-09-09 20:53:31 -05:00

7.5 KiB

startup-configuration Specification

Purpose

TBD - created by archiving change boot-config-validation. Update Purpose after archive.

Requirements

Requirement: Boot-time configuration validation

Boot-time validation SHALL run before database migrations and before any service starts, SHALL name the offending configuration key and how to set it (its MC_* environment variable or mc-config.yaml key), and a single run SHALL report every problem at once rather than only the first.

The following core configuration SHALL be required unconditionally: db-dsn (a valid PostgreSQL URL), valkey-addr, oidc-idp-issuer-url (a valid URL), oidc-sp-client-id, and base-url (a valid URL). oidc-sp-client-secret SHALL NOT be required (public PKCE clients have none). csrf-secret SHALL NOT be required and SHALL NOT be read: cross-origin protection issues no token, so there is no key to derive one from.

Scenario: Missing required core configuration is reported before migrations

  • WHEN a required core key is absent at startup
  • THEN validation SHALL fail before database migrations run
  • AND the error SHALL name the key and how to set it

Scenario: Every problem is reported at once

  • WHEN several configuration problems are present
  • THEN the command SHALL report every problem in a single aggregated error, not just the first

Scenario: A deployment that still sets csrf-secret boots normally

  • WHEN a configuration file or environment still carries csrf-secret, of any length or none
  • THEN startup SHALL ignore it and SHALL NOT fail on its value

Requirement: Declared enum values are validated at boot

For every registered configuration key that declares an enumerated value set, startup validation SHALL check that the resolved value (from flags, environment, or config file) is a member of the declared set, and SHALL report a violation in the same aggregated, actionable format as other validation failures — naming the key, the offending value, and the allowed values. Unset or empty values SHALL NOT fail this check (presence is governed by the existing required-key rules). The membership logic SHALL be shared with the operator-settings override validation so the two paths cannot diverge.

Scenario: Misspelled enum value stops the boot

  • WHEN the environment sets a declared enum key to a value outside its set (for example an auto-create flag set to "yes" where the set is "true"/"false")
  • THEN startup fails with an error naming the key, the bad value, and the allowed values, instead of booting with silently wrong behavior

Scenario: Valid and unset values pass

  • WHEN every declared enum key is unset or holds a member of its set
  • THEN validation passes exactly as before

Requirement: Transport security follows base-url

base-url SHALL carry a scheme of http or https; boot validation SHALL refuse any other scheme, naming the key and the value.

The session cookie SHALL be marked Secure exactly when base-url's scheme is https; the Content-Security-Policy SHALL carry upgrade-insecure-requests exactly when it is; and the Strict-Transport-Security header SHALL be sent exactly when it is, with a max-age of one year and includeSubDomains, never over plain HTTP (RFC 6797 section 7.2). No other configuration value, env included, SHALL affect any of the three.

Scenario: A TLS deployment under any label

  • WHEN base-url is https://… and env is any value
  • THEN the session cookie SHALL be Secure
  • AND the policy SHALL carry upgrade-insecure-requests
  • AND the response SHALL carry Strict-Transport-Security: max-age=31536000; includeSubDomains

Scenario: Plain HTTP for local work

  • WHEN base-url is http://… and env is any value, production included
  • THEN the session cookie SHALL NOT be Secure
  • AND the policy SHALL NOT carry upgrade-insecure-requests
  • AND no Strict-Transport-Security header SHALL be sent

Scenario: A scheme a browser cannot use

  • WHEN base-url is ftp://console.example.com
  • THEN boot validation SHALL fail with a message naming base-url and the value

Requirement: The session store's credentials and transport are configurable

The application SHALL require a password for the session store, supplied as a direct value or a file path but never both, and startup SHALL fail when none is configured. A session carries the person, organization and workspace ids that authorization is decided from, so a store reachable without authentication lets anyone who reaches its port read and forge them.

The application SHALL additionally accept optional configuration for a username, for connecting over TLS, and for skipping certificate verification. TLS remains optional because it requires certificates to be provisioned.

Dialling the store SHALL be bounded by connect, read and write timeouts, so an unreachable store fails the startup probe with an error rather than hanging it.

When certificate verification is disabled, the application SHALL log a warning at startup naming the deployment environment, because that setting removes the proof of who is on the other end of the connection.

Scenario: A deployment without a store password does not start

  • WHEN neither valkey-password nor valkey-password-file is configured
  • THEN startup SHALL fail, naming the key and why it is required
  • AND the failure SHALL be reported alongside any other configuration problem

Scenario: A password-protected store is reachable

  • WHEN the session store requires authentication and the password is configured
  • THEN the application SHALL connect
  • AND sessions SHALL be written to and read from it normally

Scenario: A missing password fails loudly at startup

  • WHEN the session store requires authentication and no password is configured
  • THEN startup SHALL fail with an error naming the connection failure
  • AND the application SHALL NOT begin serving

Scenario: Both a password value and a password file is rejected

  • WHEN both the password and its file path are set
  • THEN startup SHALL fail reporting the ambiguity, as it does for the other file-backed secrets

Scenario: Skipping certificate verification is announced

  • WHEN TLS is enabled and certificate verification is disabled
  • THEN startup SHALL log a warning naming the environment

Requirement: Connection strings and secrets never reach the logs

No log statement SHALL write a connection string, a password, or any key declared secret. db-dsn SHALL be a file-backed secret like the others: db-dsn-file SHALL be accepted, both set at once SHALL be reported as ambiguous, and a validation error about the value SHALL name the key and the expected shape only. A log line about a database connection SHALL carry at most host, port, database and user.

Scenario: The boot log names the database without its password

  • WHEN the console connects to the database
  • THEN the log line carries host, port, database and user and SHALL NOT contain the password

Scenario: A malformed DSN is reported without the value

  • WHEN db-dsn is not a PostgreSQL URL
  • THEN validation fails naming db-dsn and the expected postgres:// shape, and the error SHALL NOT contain the configured value

Scenario: The DSN can come from a file

  • WHEN db-dsn-file names a readable file and db-dsn is unset
  • THEN the file's contents SHALL be the DSN
  • AND setting both SHALL fail startup as an ambiguity, as for the other file-backed secrets