# Relicario Security Model

> **Audience:** auditors and curious users. This doc owns the threat model, attacker-scenarios table, device-authentication model, env-var trust surface, and known limitations. **Does NOT own:** crypto primitive details (see [CRYPTO.md](CRYPTO.md)), wire formats (see [FORMATS.md](FORMATS.md)), or implementation (see [../crates/relicario-core/ARCHITECTURE.md](../crates/relicario-core/ARCHITECTURE.md) and [../crates/relicario-cli/ARCHITECTURE.md](../crates/relicario-cli/ARCHITECTURE.md)).

## Cryptographic Protection

Relicario uses two-factor vault decryption:
1. **Passphrase** — user-memorized, zxcvbn score ≥3 required
2. **Reference image** — JPEG carrying 256-bit secret via DCT steganography

Key derivation: Argon2id (64 MiB memory, 3 iterations, 4 parallelism)
Encryption: XChaCha20-Poly1305 (192-bit nonce, 256-bit key)

## Manifest Integrity

The manifest (`manifest.enc`) is encrypted with AEAD, which provides:

- **Confidentiality**: Contents unreadable without master key
- **Integrity**: Any modification detected and rejected on decrypt
- **Authenticity**: Only master key holders can create valid ciphertexts

### What AEAD Does NOT Protect

- **Item deletion**: An attacker with write access can delete `.enc` files
  or git-revert commits. The manifest decrypts successfully but won't
  contain the deleted items.

- **Rollback attacks**: An attacker can replace `manifest.enc` with an
  older valid version. AEAD accepts any ciphertext created with the key.

### Mitigation

Item deletion and rollback are detectable via **git history**:

```bash
git log --oneline items/
```

For environments where git history could be rewritten (force-push):

1. Enable device authentication (commit signing + pre-receive hook)
2. Use a git server that rejects non-fast-forward pushes
3. Regular backups with `relicario backup export`

## Device Authentication

When enabled, device authentication provides:

- **Commit authorship**: All commits signed by registered device keys
- **Push access control**: Deploy keys managed via Gitea API
- **Instant revocation**: One command cuts off both signing and push

Enforcement requires deploying the `relicario-server` pre-receive hook
on the vault remote. The crate provides two subcommands:

- `relicario-server generate-hook` — emits the hook script to install at
  `<repo>/hooks/pre-receive`
- `relicario-server verify-commit <sha>` — checks one commit's signature
  against `.relicario/devices.json` and `.relicario/revoked.json` as of
  that commit; the hook calls this for every pushed ref

Without the server hook, signed commits provide authorship metadata only
— any process with push access can land an unsigned commit, since
verification is otherwise advisory.

See `docs/superpowers/specs/2026-05-02-device-authentication-design.md`.

## Access Control

Without device authentication, access control is transport-layer only:

- **CLI**: SSH key authentication to git remote
- **Extension**: Git credentials in browser storage

Device registration is optional but recommended for shared vaults.

## Configuration env vars

Relicario reads the following environment variables. Each is a trust
boundary: an attacker who can set them in the user's environment can
influence Relicario's behavior. They are listed here for security
reviewers to audit the surface in one place.

### User-facing (active in all builds)

| Variable | Purpose | Trust |
|---|---|---|
| `RELICARIO_IMAGE` | Override the reference-image JPEG path used during vault unlock. | Trusted: filesystem path under the user's control. Read-only; its bytes feed `imgsecret::extract_secret`. |
| `RELICARIO_GITEA_URL` | Gitea API base URL for `relicario device add`. Equivalent to `--gitea-url`. | Trusted: HTTPS URL. Used only in the device-add code path. |
| `RELICARIO_GITEA_TOKEN` | Gitea personal-access token. Equivalent to `--gitea-token`. | **Secret**: anyone who can read this env var can manage the user's deploy keys via the Gitea API. The CLI never logs it. |
| `RELICARIO_GITEA_OWNER` | Gitea repository owner (e.g. `alee`). Equivalent to `--owner`. | Trusted: opaque string. |
| `RELICARIO_GITEA_REPO` | Gitea repository name (e.g. `vault`). Equivalent to `--repo`. | Trusted: opaque string. |

### Debug-only (compiled out of `cargo build --release`)

The following variables are gated behind `cfg(debug_assertions)` and
are **no-ops** in release builds. The env-var lookup is removed by the
optimiser from any binary built without debug assertions (i.e. the
standard `--release` profile).

| Variable | Purpose |
|---|---|
| `RELICARIO_NO_GROUPS_CACHE` | Suppress the plaintext `groups.cache` write. Developer debugging tool for the cache logic. |
| `RELICARIO_TEST_PASSPHRASE` | Bypass the `rpassword` prompt during integration tests. |
| `RELICARIO_TEST_ITEM_SECRET` | Bypass the `rpassword` prompt for item-secret fields during integration tests. |
| `RELICARIO_TEST_BACKUP_PASSPHRASE` | Bypass the `rpassword` prompt for backup export/restore passphrases during integration tests. |

---

**Next:** [../crates/relicario-core/ARCHITECTURE.md](../crates/relicario-core/ARCHITECTURE.md) — implementation, starting with the platform-agnostic core.
