docs: record APT security hardening baseline

This commit is contained in:
2026-08-19 21:14:55 +00:00
parent a80074ac57
commit 1215b95df2
2 changed files with 551 additions and 0 deletions
@@ -0,0 +1,533 @@
# Alta Proxy Tool Security Foundation and Product Roadmap Implementation Plan
> **For Hermes:** Use subagent-driven-development skill to implement this plan task-by-task.
**Goal:** Remove APTs Critical/Important security and release blockers, establish a reproducible Windows baseline, recover the Mac implementation into source control, and only then open a controlled lane for new features.
**Architecture:** Keep Electrons renderer unprivileged. Move session credentials, URL validation, proxy launching, process ownership, and update verification into small main-process modules with narrow IPC contracts. Development occurs in an isolated GitPeji worktree; existing Tool Hub downloads and production surfaces remain unchanged until a fully tested, exact-commit release is approved.
**Tech Stack:** Electron, Node.js built-in `node:test`, Chrome Manifest V3 extension APIs, Electron Builder, GitPeji/Gitea Actions, SHA-256 release manifests, Windows Authenticode when available.
---
## Executive sequencing
### Phase A — Security containment and proof
No feature work enters this phase. It must close:
1. arbitrary-code self-updater;
2. CR/LF batch command injection;
3. renderer-controlled URL/cookie exfiltration;
4. cookie leakage through logs, temporary files, command lines, and broad clipboard handling;
5. stale/vulnerable Electron, Axios, and build dependencies.
### Phase B — Product/release foundation
1. canonical GitPeji source and exact tagged builds;
2. automated tests and CI;
3. reproducible Windows kit with helper provenance;
4. recover Mac source, then separately decide Intel/Rosetta versus native Apple Silicon;
5. safe, signed/digest-bound updater only after all earlier gates pass.
### Phase C — New features
Feature discovery begins only after Phase A passes independent security review and Phase B has a reproducible development build. New functions go into a written backlog with user value, permissions, data touched, risk, and acceptance tests before implementation.
## Non-negotiable guardrails
- GitPeji is the only source of truth. Do not fetch from, push to, publish on, or update from GitHub.
- Use a fresh worktree from GitPeji `master` at `a80074ac57b7a4517837b5d95754f5e6433df3ac` or newer.
- Preserve current Tool Hub downloads and production visibility until Zac approves replacement.
- Do not use real Alta cookies in automated tests; use conspicuous synthetic sentinels.
- Do not write cookies to logs, disk, command files, shell strings, crash reports, analytics, or test artifacts.
- No production release until the exact candidate passes controller verification plus independent security and release reviews.
- Mac distribution remains approval-gated under Kanban task `t_42bad4d3`.
---
## Milestone 0: Establish an isolated hardening lane
### Task 1: Create the clean GitPeji worktree and baseline evidence
**Objective:** Start from an exact, clean canonical source without modifying the archived checkout.
**Files:**
- Create worktree: `/home/peji/worktrees/apt-security-foundation`
- Create: `docs/security/2026-08-security-baseline.md`
- Reference: `/home/peji/.hermes/reports/alta-proxy-tool-full-review-2026-08-19.md`
**Steps:**
1. Fetch only GitPeji and verify `origin/master`.
2. Create branch `hardening/security-foundation` in the isolated worktree.
3. Record full starting SHA, remote, branch, clean status, dependency audit counts, current package version, and the review report path.
4. Confirm the archived checkout and Tool Hub checkout remain clean.
5. Commit only the baseline document.
**Commands:**
```bash
git fetch origin master
git worktree add -b hardening/security-foundation /home/peji/worktrees/apt-security-foundation origin/master
git -C /home/peji/worktrees/apt-security-foundation status --short --branch
```
**Expected:** clean branch based on exact GitPeji `origin/master`; no GitHub remote used.
**Commit:** `docs: record APT security hardening baseline`
---
## Milestone 1: Add a testable security boundary
### Task 2: Introduce the smallest useful test harness
**Objective:** Make security fixes test-first instead of relying on ad-hoc probes.
**Files:**
- Modify: `package.json`
- Create: `test/url-policy.test.js`
- Create: `test/error-redaction.test.js`
- Create: `test/proxy-launch.test.js`
- Create: `test/update-policy.test.js`
- Create: `test/bridge-auth.test.js`
- Create: `src/url-policy.js`
- Create: `src/error-redaction.js`
**Steps:**
1. Add `npm test` using `node --test` and `npm run check` for syntax/tests.
2. Write failing URL-policy tests for:
- HTTPS Alta subdomains accepted;
- HTTP rejected;
- non-Alta hosts rejected;
- userinfo, fragments, unexpected paths/ports, CR/LF, and malformed URLs rejected.
3. Write failing error-redaction tests proving a synthetic `va=HERMES_SENTINEL_SECRET` never appears in formatted output.
4. Implement minimal pure helpers.
5. Run tests and syntax checks.
**Commands:**
```bash
npm test
npm run check
```
**Expected:** all tests pass; no source code needs Electron to test URL/redaction logic.
**Commit:** `test: add APT security regression harness`
---
## Milestone 2: Remove the Critical updater path
### Task 3: Disable executable self-update completely
**Objective:** Remove the current arbitrary-native-code installation surface before redesigning updates.
**Files:**
- Modify: `main.js:454-630`
- Modify: `preload.js:25-37`
- Modify: `renderer.js:24-34,57-61,602-712,756-760`
- Modify: `index.html:38-41,84-106`
- Modify: `README.md:13,68-74,166`
- Test: `test/update-policy.test.js`
**Steps:**
1. Write failing source/contract tests asserting no `download-and-install-update` IPC method is exposed and no executable replacement code remains.
2. Remove updater IPC handlers, redirect downloader, executable overwrite batch script, progress event, and install controls.
3. Replace the UI with either no update control or a safe informational link to an authenticated/internal release page; do not download or execute anything.
4. Remove startup network update checks.
5. Run tests and confirm the app still starts/builds.
**Acceptance:** no renderer-to-main path can download, overwrite, or launch an executable.
**Commit:** `fix: remove unsafe in-place updater`
---
## Milestone 3: Close command injection and process-control hazards
### Task 4: Replace `.bat` construction with direct process spawning
**Objective:** Eliminate command injection and plaintext cookie batch files.
**Files:**
- Create: `src/proxy-launch.js`
- Modify: `main.js:26-31,274-387`
- Test: `test/proxy-launch.test.js`
**Steps:**
1. Write failing tests for CR/LF, shell metacharacters, malformed UUIDs, invalid domains, oversized cookie values, and missing helper.
2. Define strict input contracts:
- deployment host comes from validated main-process session state;
- device UUID matches the exact supported identifier shape;
- cookie length is bounded and never serialised into a command string;
- executable path is resolved from an approved fixed location.
3. Spawn `aware-cam-proxy.exe` directly with an argument array and `shell: false`.
4. Remove `sanitizeBatchInput()`, temporary `.bat` files, `cmd /c start`, and cookie-bearing echo output.
5. Capture only process ID, device ID, start time, and safe status metadata.
6. Add a Windows-specific smoke harness that substitutes a harmless fixture executable/script and records argv without exposing the cookie.
**Acceptance:** the CR/LF reproducer is rejected; no batch/command file exists; cookie is not printed or persisted.
**Commit:** `fix: launch proxy without shell command files`
### Task 5: Stop only APT-owned proxy processes
**Objective:** Prevent “Stop Proxy” from killing unrelated helper processes.
**Files:**
- Modify: `src/proxy-launch.js`
- Modify: `main.js:389-452`
- Modify: `renderer.js:147-177`
- Test: `test/proxy-launch.test.js`
**Steps:**
1. Write a failing test proving only tracked child process IDs are terminated.
2. Replace `taskkill /im aware-cam-proxy.exe` with tracked-process termination.
3. Return per-device stop results and remove dead entries from the process map.
4. Handle already-exited and permission-denied states honestly.
5. Verify two fixture processes: stopping one leaves the other alive.
**Commit:** `fix: scope proxy termination to APT processes`
---
## Milestone 4: Move trust and cookies into the main process
### Task 6: Replace renderer-supplied URL/cookie IPC parameters
**Objective:** Prevent a compromised renderer from sending Alta cookies to arbitrary destinations.
**Files:**
- Create: `src/session-store.js`
- Create: `src/alta-client.js`
- Modify: `main.js:192-272`
- Modify: `preload.js:5-12`
- Modify: `renderer.js:225-304,714-743`
- Test: `test/url-policy.test.js`
- Create: `test/alta-client.test.js`
**Steps:**
1. Write failing tests showing API methods reject renderer-provided URL/cookie fields.
2. Store deployment origin and cookie only in main-process memory.
3. Expose narrow IPC calls: `getDevices()`, `getDeviceSites()`, `getAuthInfo()`, `launchProxy(deviceId)`, `disconnect()`.
4. Revalidate HTTPS Alta origin inside the main process before every request.
5. Disable ambient proxy use for cookie-bearing requests unless a separately reviewed explicit enterprise-proxy configuration is later required.
6. Disable cross-origin redirects or validate every redirect before forwarding credentials.
7. Validate `event.senderFrame` against the apps local file origin/window.
8. On disconnect and app quit, overwrite references and clear session state.
**Acceptance:** renderer messages cannot choose a destination or supply/receive the bearer cookie.
**Commit:** `fix: keep Alta session authority in the main process`
### Task 7: Redact all network and process errors
**Objective:** Ensure failures cannot print cookies or secret-bearing request configuration.
**Files:**
- Modify: `src/error-redaction.js`
- Modify: `src/alta-client.js`
- Modify: `main.js`
- Test: `test/error-redaction.test.js`
**Steps:**
1. Add synthetic Axios errors containing secrets in headers, URLs, nested config, causes, and response bodies.
2. Format only bounded fields: operation, safe error code, HTTP status, timeout flag, and a sanitised message.
3. Remove all full-object `console.error(..., error)` calls from credential-bearing paths.
4. Add a source scan test for forbidden logging patterns.
5. Run a sentinel failure probe and assert zero secret occurrences in stdout/stderr.
**Commit:** `fix: redact credentials from APT errors`
---
## Milestone 5: Replace the public hard-coded bridge secret
### Task 8: Add explicit extension pairing
**Objective:** Stop treating `apt-local-bridge-token` as authentication.
**Recommended v1 design:** keep loopback temporarily but pair the extension to the desktop app with a random per-install secret and a stable extension identity. Native Messaging is a later option if portability/setup proves acceptable.
**Files:**
- Create: `src/bridge-auth.js`
- Modify: `main.js:12-145`
- Modify: `chrome-extension/manifest.json`
- Modify: `chrome-extension/popup.js`
- Create: `chrome-extension/options.html`
- Create: `chrome-extension/options.js`
- Test: `test/bridge-auth.test.js`
- Create: `test/extension-contract.test.js`
**Steps:**
1. Write failing tests for missing/wrong secret, unknown extension origin, replay/rotation, oversized body, slow body, and malformed JSON.
2. Generate a cryptographically random pairing secret and store it with user-only permissions under Electron `userData`.
3. Add a one-time pairing flow: desktop shows code; extension stores the resulting secret in `chrome.storage.local`.
4. Give the extension a stable ID and accept only that exact extension origin.
5. Compare secrets in constant time.
6. Add request/body deadlines and bounded concurrency before body reads.
7. Rotate/revoke pairing from the desktop UI.
8. Remove `apt-local-bridge-token` from source.
**Acceptance:** a different Chrome extension cannot submit data even when it knows the source code; pairing can be revoked without reinstalling APT.
**Commit:** `feat: add paired authentication for the Chrome bridge`
### Task 9: Make clipboard token copying explicitly guarded
**Objective:** Retain Zacs requested copy function without presenting it as harmless.
**Files:**
- Modify: `chrome-extension/popup.html`
- Modify: `chrome-extension/popup.js`
- Modify: `chrome-extension/popup.css`
- Test: `test/extension-contract.test.js`
**Steps:**
1. Require a deliberate confirmation for copying the full bearer token.
2. Show a concise warning that clipboard history/synchronisation may retain it.
3. Never auto-copy.
4. Clear extension references immediately after the operation.
5. Test cancellation, permission denial, missing/expired cookie, and success messaging.
**Commit:** `fix: guard VA token clipboard export`
---
## Milestone 6: Modernise dependencies and desktop hardening
### Task 10: Upgrade Electron, Axios, and packaging dependencies
**Objective:** Remove known dependency blockers without mixing in feature changes.
**Files:**
- Modify: `package.json`
- Modify: `package-lock.json`
- Modify: `main.js:148-167`
- Remove dependency if unused: `crypto-js`
- Remove/replace: `electron-packager`
**Steps:**
1. Create a dependency-upgrade branch commit separately from behaviour changes.
2. Upgrade Electron to a currently supported major compatible with the target Windows estate.
3. Upgrade Axios and transitive packages to patched releases.
4. Remove unused `crypto-js` and deprecated `electron-packager` if source/runtime scans confirm no use.
5. Enable explicit renderer sandboxing and deny unexpected navigation/window creation.
6. Run full tests, `npm audit`, Electron smoke, and Windows package build.
7. Do not accept Critical/High runtime findings; document any build-only exception with CVE reachability evidence.
**Acceptance:** zero Critical/High production audit findings; supported Electron line; app smoke passes.
**Commit:** `chore: modernize Electron runtime and dependencies`
---
## Milestone 7: Canonical source and reproducible releases
### Task 11: Add helper provenance without committing the binary blindly
**Objective:** Make the Windows kit reproducible and auditable while respecting vendor licensing.
**Files:**
- Create: `vendor/aware-cam-proxy/README.md`
- Create: `vendor/aware-cam-proxy/checksums.json`
- Modify: `build-kit.ps1`
- Modify: `README.md`
- Create: `LICENSE`
- Create: `THIRD_PARTY_NOTICES.md`
**Steps:**
1. Confirm redistribution rights for Windows/macOS helper binaries; stop if unavailable.
2. Record approved filename, platform, architecture, version/source owner, exact size, SHA-256, and acquisition procedure.
3. Make the kit build reject any helper that does not match the approved manifest.
4. Replace `author: "Your Name"` and add accurate project/third-party licensing.
5. Add ZIP content, path-safety, extension-content, executable-presence, and checksum tests.
**Commit:** `build: verify proxy helper provenance in release kits`
### Task 12: Recover Mac implementation into GitPeji source
**Objective:** Stop treating the Tool Hub Mac ZIP as source control.
**Files:**
- Recover into: `src/proxy-launch.js`
- Modify: `package.json`
- Modify: `README.md`
- Create: `docs/platforms/macos.md`
- Test: `test/proxy-launch.test.js`
**Steps:**
1. Extract and diff the current Tool Hub Mac `app.asar` against the hardened source.
2. Port only reviewed platform logic; do not copy the stripped packaged `package.json` wholesale.
3. Reuse the direct-spawn/no-shell/session rules from Windows.
4. Add explicit x64 and arm64 packaging targets, but publish only architectures with a matching approved helper.
5. Test on Intel/Rosetta and a current Apple Silicon Mac.
6. Keep Kanban `t_42bad4d3` open until native Apple Silicon/helper support is proven or Zac explicitly accepts Rosetta-only scope.
**Commit:** `feat: restore reviewed macOS source and build targets`
### Task 13: Add GitPeji CI and exact-commit release evidence
**Objective:** Build every release from one tagged GitPeji commit with retained evidence.
**Files:**
- Create: `.gitea/workflows/ci.yml`
- Create: `.gitea/workflows/release.yml`
- Remove or retire: `.github/workflows/deploy-pages.yml`
- Modify: `docs/index.html`
- Create: `scripts/verify-kit.js`
**Steps:**
1. CI gate: `npm ci`, syntax, tests, audit policy, Windows unpacked build, kit verification, secret scan.
2. Release gate: tag/version match, clean source, approved helper checksum, exact artifact hashes, SBOM, checksums, retained logs.
3. Point docs/downloads to GitPeji or the approved Tool Hub route, never GitHub.
4. Publish no artifact automatically until the first manual release rehearsal passes.
5. Rehearse on a non-production candidate tag and verify fresh download/extraction.
**Commit:** `ci: add GitPeji build and release gates`
---
## Milestone 8: Reintroduce updates safely, if still worthwhile
### Task 14: Decide whether APT actually needs in-place updates
**Objective:** Avoid rebuilding a dangerous feature merely because it existed before.
**Decision gate:**
- Preferred simplest option: notify that a verified update exists and open the trusted Tool Hub/GitPeji release page; user installs it manually.
- In-place update is allowed only if code signing, digest verification, rollback, and platform-specific testing are available.
**Deliverable:** `docs/decisions/0001-update-strategy.md`
**Commit:** `docs: decide APT update strategy`
### Task 15: Implement a verified updater only if the decision approves it
**Objective:** Bind installation to an exact trusted release.
**Files:**
- Create: `src/update-manifest.js`
- Create: `src/updater.js`
- Modify: `main.js`
- Modify: `preload.js`
- Test: `test/update-policy.test.js`
**Required tests:** wrong host, redirect host change, wrong size, wrong SHA-256, wrong signature, downgrade, wrong platform/architecture, truncated body, oversized body, interrupted download, failed replacement, successful rollback.
**Acceptance:** only a manifest-authenticated, platform-matched artifact can reach replacement code; failure leaves the installed executable intact.
**Commit:** `feat: add manifest-verified GitPeji updates`
---
## Milestone 9: Closure and controlled release
### Task 16: Run adversarial security closure review
**Objective:** Independently prove every Critical/Important finding is closed.
**Required probes:**
- arbitrary updater URL cannot execute;
- CR/LF proxy parameters cannot become commands;
- renderer cannot choose request destination or supply cookies;
- Axios failures contain no sentinel secret;
- bridge rejects unknown extension/wrong secret/slow bodies;
- cookies never appear in files, process command strings, logs, tests, ZIP metadata, or analytics;
- stop affects only APT-owned child processes;
- dependency audit and Electron support policy pass.
**Output:** finding-to-fix closure matrix with exact tests and commit.
### Task 17: Build a DEV release candidate and preserve production
**Objective:** Give Zac a testable candidate without replacing current downloads.
**Steps:**
1. Query usage/confirm release lane before changing Tool Hub visibility.
2. Build exact tagged candidate and record artifact SHA-256.
3. Publish only to an isolated DEV/download location clearly marked pre-release.
4. Run Windows app, extension pairing, device discovery, proxy launch/stop, disconnect, error, and update-notification workflows.
5. Verify current production Tool Hub/download hashes did not change.
6. Request Zac acceptance.
### Task 18: Promote only the accepted exact artifact
**Objective:** Replace the existing release safely and reversibly.
**Steps:**
1. Preserve current Windows/Mac kits and hashes as rollback artifacts.
2. Promote the exact accepted candidate—do not rebuild.
3. Verify GitPeji tag/release, Tool Hub route, download size/hash, extension contents, Windows smoke, and analytics.
4. Keep Mac separate until its own acceptance gate passes.
5. Remove temporary DEV artifacts only after production verification and rollback proof.
---
## Feature roadmap gate
### Task 19: Capture and prioritise new functions with Zac
**Objective:** Turn feature ideas into a safe, ordered backlog after the red flags are closed.
For each feature record:
- user/problem and field-engineer value;
- exact user journey;
- read versus write operations;
- Alta endpoints/data required;
- cookie/session impact;
- local helper/process impact;
- Windows/macOS parity expectation;
- failure and offline behaviour;
- acceptance tests;
- release risk and whether it can remain DEV-only.
**Suggested buckets for the discussion:**
1. **Proxy workflow improvements:** multi-camera queue, per-camera status, retry/diagnostics, safe logs.
2. **Commissioning:** thumbnail/stream health, recording/site checks, readiness report.
3. **Troubleshooting:** streams debug, recent alerts, support bundle.
4. **Operator UX:** saved non-secret deployment aliases, clearer helper detection, version/support panel.
5. **Platform:** native Apple Silicon, managed extension packaging, enterprise deployment.
Do not implement feature buckets during the hardening branch. Create separate feature branches from the accepted security foundation.
---
## Definition of “major red flags fixed”
All must be true:
- [ ] Unsafe updater removed or cryptographically verified.
- [ ] No shell/batch construction from user or renderer data.
- [ ] Main process owns deployment origin and cookies.
- [ ] Privileged IPC validates sender and strict schemas.
- [ ] No cookie in logs, files, command strings, or automatic clipboard actions.
- [ ] Loopback bridge uses revocable pairing and exact extension identity.
- [ ] Proxy stop is process-scoped.
- [ ] Supported Electron/Axios versions; no Critical/High runtime audit findings.
- [ ] Automated tests and GitPeji CI pass.
- [ ] Windows kit is exact-commit reproducible with helper provenance.
- [ ] Mac source is canonical or Mac distribution remains explicitly withheld.
- [ ] Independent security closure review returns PASS.
- [ ] Existing production/download state remains unchanged until Zac approves promotion.
@@ -0,0 +1,18 @@
# APT security hardening baseline
- Canonical source: GitPeji `peji/Alta-Proxy-Tool`
- Starting commit: `a80074ac57b7a4517837b5d95754f5e6433df3ac`
- Branch: `hardening/security-foundation`
- Original review: `/home/peji/.hermes/reports/alta-proxy-tool-full-review-2026-08-19.md`
- Implementation plan: `docs/plans/2026-08-19-apt-security-foundation.md`
- Starting package version: `1.0.0`
- Starting audit: 25 findings (1 critical, 22 high, 2 moderate); production-only audit 3 findings (2 high, 1 moderate)
- Starting release state: GitPeji/GitHub split-brain, no application CI, unsafe unsigned updater, no automated tests
## Guardrails
- GitPeji only; GitHub remote removed.
- Production Tool Hub and existing downloads remain unchanged.
- Synthetic sentinel credentials only in tests.
- Work remains on the isolated hardening branch until review gates pass.
- No feature additions until Critical/Important security closure.