# Attack surface — LexAI

> Living inventory of LexAI's exposure. Updated whenever manifest/permissions, storage, or provider handling changes, and before any Chrome Web Store push. Contains **no secrets** — only references. Maintained via the `attack-surface` skill; security review via `security-auditor`.

## Assets

| Asset | Type | Tech | Hosted | Auth in | Exposure | Defenses | Review cadence |
| --- | --- | --- | --- | --- | --- | --- | --- |
| Content script | injected code | WXT/TS | client | n/a | **`<all_urls>`, all frames** | `data-lexai` guard; inline styles; max z-index | every manifest/permission change |
| Background service worker | LLM proxy | WXT/TS | client | user's provider key | reachable only via extension messages | key never logged; provider-only fetch | every key/provider change |
| `chrome.storage.local` | local store | Chrome | client | extension-only | holds `apiKeyEnc`+`encKey` (+ legacy plaintext `apiKey`) | tweetnacl secretbox (see weakness) | every key-handling change |
| Provider endpoints | 3rd-party API | HTTPS | OpenAI/Anthropic/Groq/OpenRouter | user's API key | outbound only, user-initiated | HTTPS; key in header only | on provider add/change |
| Gitea CI | pipeline | Gitea workflows | self/3p | `GITEATOKEN`, `CWS_*`, `TELEGRAM_*` | build + publish to CWS | secrets in Gitea; **but** `http.sslVerify false` (see gap) | on workflow change |

## Per-asset notes

### Content script — `<all_urls>`
- **Exposure:** injects into every frame of every site, including banking, email, internal apps. Biggest privacy surface and the #1 Chrome Web Store review slowdown.
- **Mitigation (proposed):** narrow to `activeTab` + on-demand injection, or a user allowlist (TASKS #1 / D-PROPOSED). Decide before a serious CWS push.

### API-key storage — obfuscation, not protection
- **Exposure:** `encKey` is stored in `chrome.storage.local` next to `apiKeyEnc`; anyone who can read storage can decrypt. The "encrypted" claim over-promises.
- **Secrets location:** `chrome.storage.local` (user's own browser). Never in repo, never logged.
- **Mitigation (proposed):** derive the key from `chrome.storage.session` / WebCrypto / a passphrase, and describe it honestly in the UI (TASKS #2 / D-...-06).

### Debug logging leak
- **Exposure:** `content.ts` logs selection text and element values to the host-page console — readable by the page.
- **Mitigation:** gate behind `import.meta.env.DEV` (TASKS #3).

### CI TLS verification disabled
- **Exposure:** both Gitea workflows set `http.sslVerify false` and `git clone` into `/tmp`.
- **Mitigation:** use the checked-out workspace and restore TLS verification (TASKS #17).

## Model / harness input surface (prompt-injection)

The extension sends **user-selected page text** to the chosen LLM with a fixed system prompt. Page-controlled text is untrusted input to the provider call.

| Input avenue | Consuming model | Reachable actions | Exposure | Defense in place |
| --- | --- | --- | --- | --- |
| Selected page text → `ANALYZE_TEXT` | user's provider | returns text shown in modal; user chooses Replace/Copy | injected instructions in page text could steer the model's output | user reviews output before Replace; no tool-calling; output is inert text |

- **Note:** exposure is low because the model output is inert (no tool execution) and the user gates Replace. Run `prompt-injection-audit` if LexAI ever adds auto-apply, tool use, or agentic actions.

## Gaps / unknowns

- Host-permission narrowing not yet decided (TASKS #1).
- Key-derivation redesign not yet done (TASKS #2).
- No automated check that production builds exclude debug logs (TASKS #3).
