Files
felhom-controller/REPORT.md
T

2.0 KiB

REPORT — v0.103.0: F-C2-1 config loader no longer corrupts a bcrypt password_hash

Date: 2026-07-07 · Class: implementation (controller). Baseline: main @ cd0ebd2 (v0.102.0) → 02d37a1. Part C of the campaign-2 R1/R2 bundle.

The bug (F-C2-1, silent auth-integrity)

loadAndParse (config.go:234) and LoadFromBytes (:249) ran os.ExpandEnv over the ENTIRE YAML before parse. A bcrypt hash ($2a$10$…) is full of $word sequences, so ExpandEnv silently replaced each with its (usually empty) env value — corrupting web.password_hash on load. Proven: $2a$10$N9qo8uL…"a0". Depending on the hash this bricks login or degrades toward a bypass.

The fix

Removed both os.ExpandEnv calls — parse the raw bytes directly. The sanctioned typed env path (applyEnvOverridesFELHOM_WEB_PASSWORD_HASH, applied after parse) is unchanged; no shipped controller.yaml relies on file-level ${VAR} interpolation (only docker-compose.yml's ${DOMAIN}, which is compose-level). Behavior change: a literal ${VAR} in a value is now preserved verbatim.

Tests + red-proof

config_test.go: bcrypt hash loads byte-identical (file + bytes paths) — red-proof: pre-fix ExpandEnv mangles it to "a0" → FAIL, demonstrated + reverted; FELHOM_WEB_PASSWORD_HASH override still wins; literal ${VAR} preserved. Full gate go build/vet/test ./... = PASS.

Deploy + live acceptance

Built + pushed :0.103.0, deployed to guest 9201 (golden/bootstrap), healthy. F-C2-1 live belt: put a real bcrypt hash IN controller.yaml (the exact bug path), restarted → login with the correct password succeeded (302, no "Hibás jelszó") — the hash loaded intact; pre-fix it would corrupt → fail. Reverted controller.yaml to the auth-off pre-state (root page 200).

Observation

Migration note: any hand-edited controller.yaml carrying a ${...} that expected file-level expansion would change behavior — none exist in the repo; the golden/bootstrap writes concrete values.