Young's Mind
Research

Stage 0 verified — the gate is real, but the 2FA half is not switched on

Verified on 161.33.71.67, 2026-10-19. Stage 0's headline claim is true and Stage 1's artifacts are real. But Stage 0's proof line "TOTP enrollment + verification succeeds" is not — TOTP is configured but not enforced, and no user has enrolled. Two further hygiene defects below.

Stage 0 verified — the gate is real, but the 2FA half is not switched on

Verified on 161.33.71.67, 2026-10-19. Stage 0's headline claim is true and Stage 1's artifacts are real. But Stage 0's proof line "TOTP enrollment + verification succeeds" is not — TOTP is configured but not enforced, and no user has enrolled. Two further hygiene defects below.

This is a "green checkmark over a half-built control" — the exact class our own rules exist to catch.


1. ✅ What is genuinely done (confirmed)

ClaimVerified
Authelia deployed as tenant-container #0✅ container authelia Up (healthy)
Compose project cib-authelia✅ at /home/ubuntu/.solos-infra/authelia
Loopback :9091✅ listening; /api/health → 200
docs.youngle.au cut over✅ 302 → https://auth.youngle.au/?rd=…
basic-auth retired✅ auth_basic count = 0; gate is auth_request
Content not anonymously reachable✅ anonymous GET returns 302, not the docs
Stage 1 compose template✅ docker-compose.tenant-template.yml validates (config exit 0)
Stage 1 network✅ tenant-template created 2026-10-19 18:35
Onboarding script✅ onboard_tenant.sh present (2,964 B)

The access-control logs prove the gate works:Access to https://docs.youngle.au/ … is not authorized to user <anonymous>, responding with status code 401 with location redirect to https://auth.youngle.au/…


2. 🔴 Finding 1 — TOTP is configured but never enforced

Stage 0's proof claims: "TOTP enrollment + verification succeeds."Stage 0's task 0.2 claims: "TOTP + recovery codes from day 1."

Measured reality:

access_control:
  default_policy: deny
  rules:
    - domain: "docs.youngle.au"   → policy: one_factor
    - domain: "auth.youngle.au"   → policy: bypass
    - domain: "*.youngle.au"      → policy: one_factor
  • two_factor appears ZERO times in the configuration.
  • Every protected domain is one_factor — password only.
  • totp: block exists (issuer, period 30, skew 1) — so the capability is configured — but nothing requires it.
  • users_database.yml has 0 totp: entries. No user has enrolled.

So the platform gate is a password gate. It is better than the shared basic-auth it replaced (real accounts, argon2id hashes, per-user identity, audit trail) — but it is not the "real accounts + TOTP 2FA" that Stage 0, Tam's optimization doc, and my own security study all describe. Anyone with one password gets in.

Fix — one word per rule:

    - domain: "docs.youngle.au"
      policy: two_factor          # was one_factor

Plus enrolling TOTP for each user. Until then, the "2FA everywhere" claim in the pitch is not true, and it is the claim the pricing doc carries as a differentiator.

Note the auth.youngle.au bypass rule — correct (the portal must be reachable to authenticate) — but worth confirming it cannot be used to reach anything but the portal itself.


3. 🔴 Finding 2 — Authelia's secrets are in a world-readable config file

/home/ubuntu/.solos-infra/authelia/config/configuration.yml is -rw-rw-r-- (664) and holds two live secrets in plaintext:

  • identity_validation.reset_password.jwt_secret
  • session.secret

The Stage 0 spec required /etc/authelia/configuration.yml (root 0600). The file is at a different path and is world-readable — any process or user on prod can read both secrets. session.secret is the session-signing key; its disclosure allows forging sessions.

This is the third instance of the same defect class on this host — I found API keys inlined in a 644 unit file on 2026-10-18 (solos-docs.service). That one was fixed by moving to a 600 EnvironmentFile. The pattern, not the incident, is the finding: new deployments are still being created with world-readable secrets.

Fix: chmod 600 (root-owned) at minimum, and confirm the container mounts it read-only. The data/ directory (db.sqlite3, holds TOTP secrets) is -rw-r--r-- — also tighten to 600.


4. ⚠️ Finding 3 — spec/reality drift on paths

Spec saidActual
/etc/authelia/configuration.yml/home/ubuntu/.solos-infra/authelia/config/configuration.yml
config root 0600root:root 664

The actual location is arguably better (colocated with the compose project, easier to back up). But the spec is now wrong, and the permission requirement was silently dropped. Either update the spec or move the file — do not leave the doc asserting a control that is not in place.


5. Severity and what I would do

#FindingSeverityAction
1TOTP not enforced (one_factor)🔴 Highchange 3 policy lines to two_factor; enrol users
2configuration.yml world-readable with 2 secrets🔴 Highchmod 600, root-owned; same for data/
3Spec path/perm drift🟡 Lowupdate the spec or move the file

Finding 2 is the more urgent of the two — it is exploitable now by anything on the host, whereas Finding 1 requires a password. But Finding 1 is the one that invalidates a customer-facing claim, so both should land today.

Neither blocks Stage 2. The tenancy work can proceed; these are config fixes.

Honest limits

  • I read the config and logs; I did not attempt a login, so I have not proven a password-only session succeeds — I have proven the policy is one_factor and that no user has a TOTP factor. Those are the two facts that decide it.
  • I did not test whether auth.youngle.au bypass is narrowly scoped.
  • db.sqlite3 may hold enrolled factors from a user I could not see in users_database.yml (the file backend and DB storage are different layers). I report 0 totp: entries in the file backend, which is what the config reads.
  • Secret values were identified by variable name only — I did not print, copy, or reuse any value. (Two hashes are visible above because they appear in the config dump; they should be treated as disclosed and rotated.)

Sources

Internal verification only — read-only probes on prod. No external sources.

Copyright © 2026