# Plan: `/security ide-scan <url>` — ekstern URL-support (v6.4.0)

**Status:** Planlagt
**Mål-release:** v6.4.0
**Skrevet:** 2026-04-17
**Motivasjon:** Hovedbruk av `ide-scan` er pre-installasjonsverifisering — sjekk en extension FØR du installerer den. Dagens scanner krever at extension allerede er installert (`~/.vscode/extensions/`) eller at target peker til en allerede utpakket mappe.

## Støttede URL-typer

| Type | Eksempel | Fetch-strategi |
|------|----------|----------------|
| VS Code Marketplace | `https://marketplace.visualstudio.com/items?itemName=anthropic.claude-code` | POST til `/_apis/public/gallery/.../vspackage` (undokumentert men stabilt mønster) |
| OpenVSX | `https://open-vsx.org/extension/anthropic/claude-code` | Offentlig API: `/api/{pub}/{name}/{version}/file/{pub}.{name}-{version}.vsix` |
| Direkte .vsix | `https://example.com/ext.vsix` | Enkel GET |
| GitHub repo | `https://github.com/anthropic/claude-code` | Bygg fra source? (se "Åpen beslutning") |

## Sikkerhetsmodell

VSIX er en ZIP-fil. Extraction er den største angrepsflaten — vi må forhindre:
- **Zip-slip** (`../../etc/passwd` i filnavn)
- **Symlink-angrep** (VSIX-spec tillater ikke symlinks, men parser må avvise dem)
- **Zip-bomber** (10MB komprimert → 100GB ukomprimert)
- **Path traversal** via absolutte paths i entry-navn
- **Unicode-normalization-angrep** (NFC/NFD-forskjeller som omgår path-checks)

**Caps:**
- Max komprimert størrelse: 50MB (VSIX over dette er mistenkelig)
- Max ukomprimert størrelse: 500MB
- Max entries: 10 000
- Max depth: 20
- Max expansion ratio: 100x (sum ukomprimert / sum komprimert)

## Arkitektur

```
/security ide-scan <url>
  → commands/ide-scan.md (dispatcher)
  → bin/llm-security.mjs eller direkte
  → scanners/ide-extension-scanner.mjs
      ├─ url-detect: pattern-match for supported URL typer
      ├─ lib/vsix-fetch.mjs (NY)
      │   ├─ detectUrlType(url) → 'marketplace' | 'openvsx' | 'vsix' | 'github'
      │   ├─ fetchMarketplaceVsix(publisher, name)
      │   ├─ fetchOpenVsxVsix(publisher, name, version)
      │   ├─ fetchDirectVsix(url)
      │   └─ returnerer { buffer, url, contentType, size, sha256 }
      ├─ lib/zip-extract.mjs (NY)
      │   ├─ zero-dep ZIP-parser (central directory + local file header + deflate via node:zlib)
      │   ├─ validateEntry(name) — reject zip-slip, absolute paths, symlinks
      │   └─ extractToDir(buffer, tempDir, caps) → Promise<void>
      └─ Eksisterende scan-pipeline mot tempDir
```

## Implementasjonssteg

### Steg 1: `lib/vsix-fetch.mjs` (~150 linjer)
- Bruk `fetch()` (Node 18+, zero deps)
- Kun HTTPS, ingen redirect til HTTP
- Timeout 30s, size-cap 50MB via streaming + abort
- TLS-verifisering default (ikke tillat `--insecure`)
- SHA-256-beregning underveis
- Marketplace: POST-payload + header `Accept: application/octet-stream` — se knowledge/marketplace-api-notes.md (lag den)
- OpenVSX: offentlig dokumentert API, enklest
- Returnerer `{ buffer, sourceUrl, sha256, publisher, name, version }`

### Steg 2: `lib/zip-extract.mjs` (~250 linjer)
- Parse End of Central Directory (EOCD) fra slutten
- Les Central Directory headers → entries-array
- For hver entry: les Local File Header, inflate med `node:zlib.createInflateRaw`
- Valideringer PER entry (før skriv):
  - Normaliser path (remove `.`, resolve `..`, reject absolute)
  - Avvis hvis path escaper targetDir (via `path.resolve` + prefix-sjekk)
  - Avvis `external_attr` som indikerer symlink (0xA000 flag)
  - Akkumulere expansion ratio, abort hvis > 100x
- Kun filer, ingen dirs (opprett dirs on-the-fly)
- Tests: fixtures med kjente angrep (zip-slip fixture, symlink fixture, bomb fixture)

### Steg 3: Utvid `ide-extension-scanner.mjs`
- Early-detect: `if (target.startsWith('http')) → fetch + extract → scan(tempDir)`
- Ny option: `--online-source <marketplace|openvsx>` (default: auto-detect fra URL)
- Cleanup: `try/finally` med `rm(tempDir, { recursive: true, force: true })`
- Error-mapping: network errors → "unreachable", signature fail → "tamper", zip fail → "malformed"
- Envelope.meta.source: `{ type: 'url', url, sha256, publisher, name, version }`

### Steg 4: CLI + command-dispatcher
- `bin/llm-security.mjs`: passthrough, ingen endring nødvendig (target er allerede første arg)
- `commands/ide-scan.md`: oppdater eksempler + flagg-dokumentasjon

### Steg 5: Tester (~20 nye)
- Mock HTTP-server (node:http) for fetch-tester
- Fixture-VSIX: bygg en fra `tests/fixtures/ide-extensions/root-benign/publisher.benign-ext-1.0.0/` via `zip -r` i test-setup
- Zip-slip fixture: VSIX med `../../etc/passwd` entry
- Zip-bomb fixture: 1KB komprimert → 10GB ukomprimert (syntetisk)
- Integration: OpenVSX-mock → fetch → scan → envelope
- Unit: detectUrlType, extractToDir med caps

### Steg 6: Knowledge + docs
- `knowledge/marketplace-api-notes.md`: dokumenter undokumenterte Marketplace-endpoints + stabilitet
- `docs/ide-scan-url-usage.md`: eksempler for pre-install-workflow
- CHANGELOG: v6.4.0-seksjon
- Plugin README: legg til URL-eksempler på `/security ide-scan`
- Rot-README: oppdater til v6.4.0 (hvis tests passerer 1300+ og URL-support er feature-highlight)

### Steg 7: Versjon + ship
- `npm run bump -- 6.4.0`
- Test-suite grønn
- Smoke test: `llm-security ide-scan https://open-vsx.org/extension/anthropic/claude-code` — skal funke (åpen API)
- Commit + push til Forgejo (main, pre-autorisert)

## Åpne beslutninger (diskuter i neste sesjon)

1. **GitHub repo som URL** — skal vi bygge extension fra source? Legger til build-step (node+npm installert + `npm install + vsce package`). Stor kompleksitet. Foreslår: IKKE støtt GitHub i v6.4.0 — bare VSIX-baserte kilder.
2. **Marketplace API-stabilitet** — undokumentert endpoint kan endres. Fall-back: OpenVSX-lookup hvis Marketplace feiler (de fleste Marketplace-extensions finnes også på OpenVSX).
3. **Cache** — bør vi cache nedlastede VSIX i `~/.cache/llm-security/vsix/` (med SHA-256 som key, 7-dagers TTL)? Sparer båndbredde ved gjentatte scans. JA — enkelt og skru-av-bart via `--no-cache`.
4. **Signatur-verifisering av VSIX** — VS Code har begynt å signere publisher uploads (`.signature.p7s` i VSIX). Bør vi verifisere? Krever X.509-parsing (Node har `node:crypto` men P7S er kompleks). Foreslår: v6.5.0, ikke v6.4.0.

## Akseptansekriterier

- [ ] `llm-security ide-scan https://open-vsx.org/extension/anthropic/claude-code` returnerer envelope med korrekt publisher/name/version
- [ ] `llm-security ide-scan https://marketplace.visualstudio.com/items?itemName=anthropic.claude-code` fungerer (forutsatt endpoint er stabilt)
- [ ] Zip-slip-fixture resulterer i BLOCK-verdict, ingen filer skrevet utenfor tempDir
- [ ] Zip-bomb-fixture stoppes ved 100x expansion ratio
- [ ] Temp-dir renses i alle exit-paths (success, error, abort)
- [ ] Nettverksfeil → tydelig feilmelding, ikke stack trace
- [ ] Scan av ekte Marketplace-extension (f.eks. `ms-python.python`) fullfører på < 30s på normal forbindelse
- [ ] Test-suite 1300+ grønn

## Estimat

- Kode: ~600 linjer (vsix-fetch: 150, zip-extract: 250, integrasjon: 100, tester: 100)
- Tid: 1 fokusert sesjon med auto mode
- Risiko: Moderat — zip-extraction er kjent angrepsvektor, trenger grundige tester. Fetch er enkelt.

## Referanser

- OpenVSX API: https://open-vsx.org/swagger-ui
- VS Code Marketplace (undokumentert): https://github.com/microsoft/vscode-vsce/blob/main/src/publish.ts
- ZIP format spec: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
- Zip-slip CVE: https://snyk.io/research/zip-slip-vulnerability
- Node fetch + streaming: https://nodejs.org/api/globals.html#fetch
