# Patch Analysis — CVE-2026-58466 (AutoBangumi default admin credentials)

## Ticket-referenced fix

The CVE advisory lists **AutoBangumi 3.2.8** as the patched version. The parent
RCA identified the fix commit referenced by the advisory as
**`487bdfec545e805ae416e6ddf28651bd274d6a73`**
(*"fix(api): harden pre-auth setup endpoints (#1041, #1044)"*), released in the
3.2.8 batch (`952e1e3e` *"fix: batch 3.2.8 — qB 5.2 login, torrent deletion, setup
hardening, RSS throttling"*), tag `3.2.8` → `265b449fad6d753f061a09aaa03fcd3eb739a266`.

Repository: `https://github.com/EstrellaXD/Auto_Bangumi.git`
Inspected ref (project cache): `main` @ `b090ec7b02fd91a10bf45c7702ad392ae3ad65ef` (`3.2.8-4`).

## What the fix changes

`git show 487bdfec` and the 3.2.8 changelog show the change is confined to
**`backend/src/module/api/setup.py`** (the pre-auth `/setup/test-*` wizard
endpoints) and the qBittorrent client:

1. `test_downloader` / `test_rss` now validate the URL scheme via
   `_validate_scheme()` / `_validate_url()`, rejecting non-`http`/`https`
   schemes and (for `test_rss`) private/reserved/loopback IPs — i.e. an
   **SSRF** hardening of the pre-auth setup probes (#1041).
2. Raw exception strings are no longer echoed to the unauthenticated caller
   ("所有 setup 接口不再回显原始错误详情") — information-leak reduction.
3. qBittorrent ≥ 5.2 login compatibility (HTTP 204 empty body) and connection
   pool leak fixes (#1044/#1034/#1043) — unrelated downloader fixes.

**The fix touches none of:**
- `backend/src/module/database/user.py` (`UserDatabase.add_default_user`)
- `backend/src/module/api/auth.py` (`POST /api/v1/auth/login`)
- `backend/src/module/security/api.py` (`get_current_user`, `check_login_ip`)
- `backend/src/module/update/startup.py` (startup seeding trigger)

## Fix assumption / invariant

The implicit assumption is that the pre-auth attack surface to harden is the
**SSRF** reach of `/setup/test-downloader` / `/setup/test-rss`. The fix assumes
that closing the SSRF/information-leak on the setup probes is the security-relevant
change for 3.2.8. It makes **no assumption about, and provides no remediation for,
the hard-coded default `admin`/`adminadmin` account** that `add_default_user()`
seeds on every empty-database startup, nor about the `/api/v1/auth/login`
endpoint being reachable with those credentials before/without completing setup.

## Code paths the fix covers vs. does NOT cover

| Path | Covered by 487bdfec / 3.2.8? |
|---|---|
| `/api/v1/setup/test-downloader` SSRF (scheme/host) | ✅ hardened |
| `/api/v1/setup/test-rss` SSRF (scheme/private IP) | ✅ hardened |
| Setup error-detail leak | ✅ reduced |
| `add_default_user()` seeding `admin`/`adminadmin` | ❌ **unchanged** |
| `POST /api/v1/auth/login` accepting default creds | ❌ **unchanged** |
| `POST /api/v1/setup/complete` pre-auth admin-account reset | ❌ **unchanged** |
| `get_current_user` three-tier auth (DEV/Bearer/Cookie) | ❌ unchanged |
| `check_login_ip` (empty whitelist = allow all) | ❌ unchanged |

### Source-identity confirmation (byte-level)

`git diff` of the root-cause and login files across the version range:

- `backend/src/module/database/user.py`: `3.2.6..HEAD` — **no content change to
  `add_default_user()`** (still `User(username="admin", password=get_password_hash("adminadmin"))`
  on an empty users table). `3.2.6..3.3.0-beta.2` only refactors the session to
  async (`AsyncSession`, `await`) — the seeding logic and the hard-coded
  credential constant are identical.
- `backend/src/module/api/auth.py`: `3.2.6..HEAD` — **no change to the `login()`
  handler logic** (`User(...) → auth_user → _issue_token`); `3.3.0-beta.2` only
  adds `samesite="strict"` to the cookie and changes `/logout` from GET→POST
  plus `_API_TOKEN_USER` handling. **No setup-completion gate is added to
  `/auth/login`** (`grep _require_setup_needed auth.py` → none).
- `backend/src/module/security/api.py`: `3.2.6..HEAD` — no change; `3.3.0-beta.2`
  refactors `active_user` to a custom container. The `DEV_AUTH_BYPASS` /
  Bearer / Cookie three-tier logic is preserved.

Therefore the exact exploit from the parent RCA (default-credential login) is
**byte-compatible** from 3.2.6 through the latest tag `3.3.0-beta.2`
(`c8f402fd`) and `main` HEAD (`b090ec7b`).

## Behavior before vs. after the fix

| Behavior | 3.2.6 (vuln) | 3.2.8 (claimed patch) | 3.3.0-beta.2 (latest) |
|---|---|---|---|
| Fresh empty DB seeds `admin`/`adminadmin` | ✅ | ✅ (still) | ✅ (still) |
| `/api/v1/auth/login` admin/adminadmin → 200 + admin JWT | ✅ | ✅ (still) | ✅ (still) |
| JWT cookie → admin API (`/api/v1/rss`, `/api/v1/log`) | ✅ | ✅ (still) | ✅ (still) |
| `/api/v1/setup/complete` pre-auth resets admin account | ✅ | ✅ (still) | ✅ (still) |
| `/setup/test-rss` SSRF to private IPs | ❌ vuln | ✅ blocked | ✅ blocked |

The fix's SSRF hardening works, but it is **orthogonal** to CVE-2026-58466.
The default-credential seeding and the pre-auth admin-account reset are
unaffected — the patch is **incomplete / ineffective for this CVE**.

## Target threat model (SECURITY.md)

`SECURITY.md` only defines supported versions (3.x supported, <3.0 not) and a
private reporting process. It does **not** state that default credentials, the
first-run setup wizard, or pre-auth setup endpoints are out of scope. There is
no documented threat model excluding "fresh-instance takeover" or "default
credentials." Consequently the variant findings below are within the target's
stated security scope (default credentials / missing authentication for a
critical admin function are not disclaimed).

## Gap summary for a complete fix

A complete remediation of CVE-2026-58466 must, at minimum:

1. **Stop seeding a hard-coded default admin.** Either require the setup wizard
   to create the first admin (no `add_default_user()` seeding of a known
   password), or generate a random one-time bootstrap password surfaced once
   to the operator.
2. **Gate `POST /api/v1/auth/login` behind setup completion**
   (`config/.setup_complete` sentinel) so login is rejected until the operator
   has configured the instance — closing Variant 1.
3. **Bind a setup token / one-time bootstrap secret to
   `POST /api/v1/setup/complete`** (or otherwise authenticate the first-run
   takeover) so an unauthenticated remote party cannot reset the admin account
   on a fresh instance — closing Variant 2.
4. Add a regression test asserting a fresh empty DB never contains a
   login-capable account with a known password and that `/auth/login` fails
   before setup completion.

The 3.2.8 fix (SSRF hardening) satisfies none of these for the
default-credentials CVE, which is why both variants below reproduce on the
patched **and** latest images.
