<!-- canonical: https://docs.axelabs.ai/ops/reports/timshel-vaultwarden-upstream-pr-2026-05 -->
<!-- source: content/ops/reports/timshel-vaultwarden-upstream-pr-2026-05.mdx -->

---
title: Timshel/vaultwarden upstream PR draft — bw 2026.4+ client compatibility (2026-05)
description: AXE Labs 가 Timshel fork 의 axe.2 release 에 적용한 2 patch 의 upstream 제출 draft. /accounts/prelogin/password alias + /identity/connect/token AccountKeys/MasterPasswordUnlock backport. 둘 다 dani-garcia/vaultwarden mainline backport 성격.
---

# Timshel/vaultwarden upstream PR draft — bw 2026.4+ client compatibility (2026-05)

> **상태**: Draft. 운영자 검토 후 [Timshel/vaultwarden](https://github.com/Timshel/vaultwarden) 에 그대로 PR 본문으로 paste 가능한 self-contained 제출문.
>
> **Backlog**: [B-vault-axe.2-patches-upstream-pr](/ops/backlog) · **관련 분석**: [/ops/known-gaps](/ops/known-gaps) 의 Timshel fork drift 항목.
>
> **Scope**: 본 PR 은 axe.2 의 2 patch 만 다룸. axe.3 의 organizations Owner-skip 제거 + cipher.permissions backport 는 별 PR 권장 (§7 참조).

---

## 1. Summary

Timshel/vaultwarden fork 가 dani-garcia/vaultwarden mainline 대비 2개 endpoint 가 outdated → bw CLI 2026.4+ / Bitwarden Chrome extension >= 2026.4 와 호환 깨짐. 본 PR 가 2 minimal patch 로 mainline 동등 shape 회복.

## 2. Motivation

### 2.1 Symptom

- bw CLI `2025.7.0` 까지는 호환 정상.
- bw CLI `2026.4.x` + Bitwarden Chrome ext `2026.4+` 에서 SSO user unlock 시도 시 다음 에러:
  - `Master password unlock data was not found`
  - `Cannot read properties of null (reading 'toWrappedAccountCryptographicState')`

### 2.2 Trigger

새 Bitwarden client (2026.4.x) 가 unlock flow 에서 server 측 응답 shape 의존성 강화 (mainline vaultwarden 의 새 spec). Timshel 은 옛 spec 유지 → 새 client 가 expect 하는 field 부재로 unlock 차단.

### 2.3 Affected

- Timshel fork 사용자 + 2026.4.x bw client 조합.
- SSO 인증 후 master password unlock 흐름.

### 2.4 Workaround (현재 운영)

- 클라이언트 측: `npm install -g @bitwarden/cli@2025.7.0` 으로 pin (임시).
- 서버 측 (영구): 본 PR 의 2 patch 적용 — AXE Labs 는 axe.2 release 로 production 운영 중.

## 3. Changes

### 3.1 Patch 0001 — `/accounts/prelogin/password` alias

**File**: `src/api/identity.rs` (또는 동등 router).

**Change** (개념):

```rust
// 기존
.route("/accounts/prelogin", post(prelogin))

// 추가
.route("/accounts/prelogin/password", post(prelogin))  // mainline alias
```

또는 동일 handler 가 두 path 모두 처리하도록 등록.

**Rationale**: dani-garcia/vaultwarden mainline 의 `/accounts/prelogin/password` endpoint 와 동일 response shape. bw 2026.4 client 가 본 path 호출 → 200 OK + shape (kdf, kdfIterations 등) 받아 unlock 진행.

### 3.2 Patch 0002 — `/identity/connect/token` AccountKeys/MasterPasswordUnlock

**File**: `src/api/identity.rs` (또는 connect_token handler).

**Change** (개념):

```rust
struct TokenResponse {
    // ... 기존 field
    AccountKeys: AccountKeysData,         // 신규
    MasterPasswordUnlock: MpUnlockData,   // 신규
}

struct AccountKeysData {
    publicKey: String,
    encryptedPrivateKey: String,
    // ... mainline 동등
}

struct MpUnlockData {
    kdf: KdfType,
    kdfIterations: i32,
    kdfMemory: Option<i32>,
    kdfParallelism: Option<i32>,
    salt: String,
    masterKeyWrappedUserKey: String,
    emailKdfIterations: Option<i32>,
    // ... mainline 동등
}
```

**Rationale**: mainline vaultwarden 의 `/identity/connect/token` response 와 동일 field set. 2026.4+ client 가 본 field 로 unlock flow 진행.

## 4. Testing

### 4.1 Manual verification (AXE Labs production, 2026-05-26)

Server 측 (axe.2 image deploy 후):

```bash
curl -X POST https://axe.axelabs.ai/vault/api/accounts/prelogin/password \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com"}'
# Expected: 200 OK + {kdf, kdfIterations, ...}
```

Client 측 (bw CLI 2026.4+):

```bash
bw config server https://axe.axelabs.ai/vault
bw login --sso
# Expected: SSO + MP flow 통과, unlock 성공
```

### 4.2 Real-world validation

- AXE Labs production 운영 (2026-05-26 부터): axe.2 image deploy 후 bw CLI 2026.4.x + Chrome ext 2026.4.x 모두 정상 unlock 검증.
- Real users: 4 명 (운영자 + 3 임직원) — 회귀 0 보고.

## 5. Compatibility

- **Backward compat**: 기존 `/accounts/prelogin` 그대로 유지 → 옛 client (2025.x 이하) 영향 0.
- **Forward compat**: mainline vaultwarden 의 shape 와 동등 → 미래 client update 와도 정합.
- **Database migration**: 없음 — 모두 response shape 변경만.

## 6. Code reference

AXE Labs 의 fork repo: https://github.com/axelabs-ai/vault

- axe.2 release commit: TBD (운영자가 commit hash 채울 것)
- `patches/0001_prelogin_password_alias.patch`
- `patches/0002_connect_token_account_keys_mp_unlock.patch`

Mainline reference:

- dani-garcia/vaultwarden 의 동등 코드 위치 (PR 제출 시 commit/file 링크 첨부 권장).

## 7. Related (별 PR 권장)

axe.3 release 의 추가 2 patch — 본 PR scope 외:

- **Patch 0003**: organizations Owner-skip 3 site removal — `post_organization_collections` + `post_bulk_access_collections` + `post_organization_collection_update` 의 `if member.access_all { continue; }` 제거 → Owner 도 명시 users_collections row 생성.
- **Patch 0004**: `cipher.rs::to_json` User-sync branch 에 `permissions: {response: null, delete: <bool-escape>, restore: <bool-escape>}` 추가.

위 2 patch 는 organization permission model 의 mainline 정합 — 별 PR 로 분리 제출 권장 (review surface 분리 + 본 PR 의 compatibility-only 성격 유지).

## 8. Status

| Field | Value |
|---|---|
| Report state | Draft |
| 작성 일자 | 2026-05-28 |
| 제출 일자 | TBD (운영자 결정) |
| Timshel upstream 회신 | TBD |
| 수락 시 효과 | AXE fork 의 axe.2 diff 자연 소실 (`B-vault-axe.2-sso-mp-incomplete` archive) |

## 9. Submission channels

- **Repo**: https://github.com/Timshel/vaultwarden
- **PR title**: `Backport prelogin/password alias + connect/token AccountKeys/MasterPasswordUnlock from dani-garcia mainline (bw 2026.4+ compatibility)`
- **Label 권장**: `compatibility`, `mainline-backport`

운영자가 검토 후 위 채널로 PR 제출. 회신 수령 시 본 페이지 §8 표를 갱신하고 [/ops/backlog](/ops/backlog) 의 `B-vault-axe.2-patches-upstream-pr` 를 ✅ 로 이동.
