# Bug Log - LastID Rust SDK

Track bugs with security assessments, root cause analysis, and fix verification.

---

## Template

```markdown
# [BUG-ID] Title: Brief, Technical Summary

**Status:** `DRAFT | TRIAGED | IN-PROGRESS | VERIFYING | CLOSED`
**Priority:** `P0 (Critical/Blocker) | P1 (High) | P2 (Medium)`
**Impact Area:** `[e.g., Memory Safety | Logic | Cryptography | AuthN/Z | Cross-Platform]`

---

## Security Assessment
* **CWE ID:** [e.g., CWE-416: Use After Free]
* **CVSS Score:** [Score 0-10]
* **Potential Exploit:** [Describe if this vulnerability is reachable via external input]

## Description
**Actual Behavior:** > Detailed technical description of the failure.

**Expected Behavior:** > Definition of "Correct" state according to the specification.

## Reproduction Environment
* **Compiler:** `rustc [version]` | **Target:** `[e.g., wasm32-unknown-unknown]`
* **Crate Version:** `vX.Y.Z`
* **Feature Flags:** `[e.g., --features wasm]`

### Steps to Reproduce
1. [Step 1]
2. [Step 2]
3. `cargo test --test [test_name] -- --nocapture`

## Root Cause Analysis (RCA)
*Detailed explanation of the underlying failure.*

## Fix Verification Requirements
- [ ] Regression test added to `tests/`.
- [ ] All platform targets compile (`cargo build --target <target>`).
- [ ] `cargo clippy --all-features -- -D warnings` passes.
- [ ] Coverage remains at 95%+.
- [ ] Peer review completed.
```

---

## Active Bugs

*No active bugs logged yet.*

---

## Resolved Bugs

### [BUG-003] WebSocket vp_token Array Deserialization Failure

**Status:** `CLOSED`
**Priority:** `P1 (High)`
**Impact Area:** `Cross-Platform | WebSocket | Serialization`

---

#### Security Assessment
* **CWE ID:** CWE-436: Interpretation Conflict
* **CVSS Score:** 3.7 (Low) - Availability impact only, no data exposure
* **Potential Exploit:** None - functional bug, not security vulnerability

#### Description
**Actual Behavior:** When IDP sent `vp_token` as an array (for multi-credential presentations), the SDK's serde deserialization failed with:
```
[NETWORK_ERROR] Message parse error: invalid type: sequence, expected a string
```

**Expected Behavior:** SDK should accept both string and array formats for `vp_token`, as the IDP TypeScript interface allows either:
```typescript
vp_token?: string | string[]; // Single JWT or array for multi-credential presentations
```

#### Reproduction Environment
* **SDK:** lastid-rust-sdk v0.1.0 (WASM build)
* **IDP:** gettrusted-idp
* **Feature Flags:** `--features wasm,websocket`

##### Steps to Reproduce
1. Build WASM SDK with WebSocket feature
2. Open workbench, connect to IDP
3. Request a multi-credential presentation
4. IDP sends `vp_token: ["token1", "token2"]`
5. SDK fails with parse error

#### Root Cause Analysis (RCA)
IDP's `verification-handler.ts` defined:
```typescript
export interface VerificationStatusPayload {
  vp_token?: string | string[];  // Can be array
}
```

But SDK's `VerificationStatusPayload` only accepted String:
```rust
#[serde(default)]
pub vp_token: Option<String>,  // ❌ Only accepts string
```

#### Fix Applied
Added custom serde deserializer `deserialize_string_or_vec` that accepts both formats:

```rust
#[serde(default, deserialize_with = "deserialize_string_or_vec")]
pub vp_token: Option<String>,

fn deserialize_string_or_vec<'de, D>(deserializer: D) -> Result<Option<String>, D::Error> {
    // Accepts: string, array of strings (joined with ~), or null
}
```

Arrays are joined with `~` (standard VP token separator for multi-credential presentations).

#### Fix Verification
- [x] 5 regression tests added: `test_vp_token_as_string`, `test_vp_token_as_array`, etc.
- [x] All tests pass with `--features websocket`
- [x] Handles: string, array, null, missing, empty array

**Resolved:** 2026-01-18
**File Modified:** `src/http/websocket/messages.rs`

---

### [BUG-002] WebSocket Message Type Mismatch Breaks WASM Subscription

**Status:** `CLOSED`
**Priority:** `P1 (High)`
**Impact Area:** `Cross-Platform | WebSocket | Integration`

---

#### Security Assessment
* **CWE ID:** CWE-436: Interpretation Conflict
* **CVSS Score:** 3.7 (Low) - Availability impact only, no data exposure
* **Potential Exploit:** None - functional bug, not security vulnerability

#### Description
**Actual Behavior:** When WASM SDK connects via `wss://idp/ws?request_id=xxx`, the IDP sent a `verification.subscribed` message type that the SDK's `WsMessage` enum did not recognize. Serde deserialization failed with `MessageParseError`, causing the WebSocket subscription to fail immediately.

**Expected Behavior:** SDK should successfully establish WebSocket subscription and receive `verification.status` updates.

#### Reproduction Environment
* **SDK:** lastid-rust-sdk (WASM build)
* **IDP:** gettrusted-idp
* **Feature Flags:** `--features wasm,websocket`

##### Steps to Reproduce
1. Build WASM SDK with WebSocket feature
2. Open workbench, connect to IDP
3. Request credential verification
4. WebSocket connection fails with parse error

#### Root Cause Analysis (RCA)
The IDP `server.ts` (line 279) sent `verification.subscribed` as initial confirmation:
```javascript
ws.send(JSON.stringify({
  type: 'verification.subscribed',  // ❌ Not in SDK's WsMessage enum
  payload: { request_id, message: '...' },
}));
```

SDK's `WsMessage` enum only recognized:
- `verification.status`
- `error`

The mismatch caused serde to fail parsing the first message.

#### Fix Applied
Changed IDP `server.ts` to send `verification.status` with `state: 'pending'` instead:
```javascript
ws.send(JSON.stringify({
  type: 'verification.status',  // ✅ SDK recognizes this
  payload: { request_id, state: 'pending' },
}));
```

This aligns with what `verification-handler.ts` already sends for subsequent status updates.

#### Fix Verification
- [x] IDP sends `verification.status` with `state: pending` on connection
- [x] SDK's existing `WsMessage::VerificationStatus` variant handles it
- [x] `StatusUpdate::from_message()` maps `pending` state correctly
- [ ] Integration test with workbench

**Resolved:** 2026-01-18
**File Modified:** `gettrusted-idp/src/api/websocket/server.ts:275-284`

---

### [BUG-001] Improper Zeroization in SigningKeyWrapper

**Status:** `CLOSED`
**Priority:** `P1 (High)`
**Impact Area:** `Cryptography | Memory Safety`

---

#### Security Assessment
* **CWE ID:** CWE-226: Sensitive Information in Resource Not Removed Before Reuse
* **CVSS Score:** 4.7 (Medium) - Local access required, limited exploitability
* **Potential Exploit:** Attacker with memory access (debugger, core dump, cold boot attack) could recover original private key material after the key was "zeroized"

#### Description
**Actual Behavior:** The `SigningKeyWrapper::zeroize()` implementation replaced the key with fresh random data instead of zeroing memory:

```rust
impl Zeroize for SigningKeyWrapper {
    fn zeroize(&mut self) {
        use rand::rngs::OsRng;
        // WRONG: Overwrites with random, does not zero original
        self.0 = SigningKey::random(&mut OsRng);
    }
}
```

**Expected Behavior:** Memory containing private key material should be overwritten with zeros using volatile writes that cannot be optimized away by the compiler.

#### Root Cause Analysis (RCA)
The `p256::ecdsa::SigningKey` implements `ZeroizeOnDrop` but not `Zeroize` directly. The original implementation worked around this by replacing the key with random data, but this approach:
1. Did not actually remove the original key from memory
2. Required RNG during cleanup (potential failure point)
3. Was not deterministic or verifiable

#### Fix Applied
Restructured `SigningKeyWrapper` to store raw scalar bytes in `Zeroizing<[u8; 32]>`:

```rust
struct SigningKeyWrapper {
    key: SigningKey,
    scalar_bytes: Zeroizing<[u8; P256_SCALAR_SIZE]>,
}

impl Zeroize for SigningKeyWrapper {
    fn zeroize(&mut self) {
        self.scalar_bytes.zeroize();  // Uses volatile writes
    }
}
```

Also added:
- `ZeroizeStrategy` trait for custom zeroization (HSM, secure allocators)
- `DefaultZeroizeStrategy` using the zeroize crate
- Comprehensive documentation of security limitations
- 10+ new tests verifying zeroization behavior

#### Fix Verification
- [x] Regression tests added: `test_signing_key_wrapper_zeroize_zeros_bytes`, etc.
- [x] All 239 library tests pass
- [x] Clippy clean for dpop module
- [x] Documentation updated with OWASP references

**Resolved:** 2026-01-18
**Commit:** (pending)
