From 6cdbd58616d813aa430cb2f575ed4e0f41ed09e9 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Tue, 24 Mar 2026 15:13:19 -0700 Subject: [PATCH 1/2] fix: random UUID installation_id + gitignore supabase/.temp Replace SHA-256(hostname+user) with random UUID v4 stored in ~/.gstack/installation-id. Not derivable from public inputs. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitignore | 1 + bin/gstack-telemetry-log | 29 ++++++++++++++++++++--------- test/telemetry.test.ts | 4 ++-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 189276fb6..770818be3 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ bun.lock .env.local .env.* !.env.example +supabase/.temp/ diff --git a/bin/gstack-telemetry-log b/bin/gstack-telemetry-log index edcbdbabf..885dfc2b2 100755 --- a/bin/gstack-telemetry-log +++ b/bin/gstack-telemetry-log @@ -106,18 +106,29 @@ if [ -d "$STATE_DIR/sessions" ]; then fi # Generate installation_id for community tier +# Uses a random UUID stored locally — not derived from hostname/user so it +# can't be guessed or correlated by someone who knows your machine identity. INSTALL_ID="" if [ "$TIER" = "community" ]; then - HOST="$(hostname 2>/dev/null || echo "unknown")" - USER="$(whoami 2>/dev/null || echo "unknown")" - if command -v shasum >/dev/null 2>&1; then - INSTALL_ID="$(printf '%s-%s' "$HOST" "$USER" | shasum -a 256 | awk '{print $1}')" - elif command -v sha256sum >/dev/null 2>&1; then - INSTALL_ID="$(printf '%s-%s' "$HOST" "$USER" | sha256sum | awk '{print $1}')" - elif command -v openssl >/dev/null 2>&1; then - INSTALL_ID="$(printf '%s-%s' "$HOST" "$USER" | openssl dgst -sha256 | awk '{print $NF}')" + ID_FILE="$HOME/.gstack/installation-id" + if [ -f "$ID_FILE" ]; then + INSTALL_ID="$(cat "$ID_FILE" 2>/dev/null)" + fi + if [ -z "$INSTALL_ID" ]; then + # Generate a random UUID v4 + if command -v uuidgen >/dev/null 2>&1; then + INSTALL_ID="$(uuidgen | tr '[:upper:]' '[:lower:]')" + elif [ -r /proc/sys/kernel/random/uuid ]; then + INSTALL_ID="$(cat /proc/sys/kernel/random/uuid)" + else + # Fallback: random hex from /dev/urandom + INSTALL_ID="$(od -An -tx1 -N16 /dev/urandom 2>/dev/null | tr -d ' \n')" + fi + if [ -n "$INSTALL_ID" ]; then + mkdir -p "$(dirname "$ID_FILE")" 2>/dev/null + printf '%s' "$INSTALL_ID" > "$ID_FILE" 2>/dev/null + fi fi - # If no SHA-256 command available, install_id stays empty fi # Local-only fields (never sent remotely) diff --git a/test/telemetry.test.ts b/test/telemetry.test.ts index c9b424736..a30506316 100644 --- a/test/telemetry.test.ts +++ b/test/telemetry.test.ts @@ -78,8 +78,8 @@ describe('gstack-telemetry-log', () => { const events = parseJsonl(); expect(events).toHaveLength(1); - // installation_id should be a SHA-256 hash (64 hex chars) - expect(events[0].installation_id).toMatch(/^[a-f0-9]{64}$/); + // installation_id should be a UUID v4 (or hex fallback) + expect(events[0].installation_id).toMatch(/^[a-f0-9-]{32,36}$/); }); test('installation_id is null for anonymous tier', () => { From 312b14827e3d9e38c07622c74f81cef99f759dae Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Tue, 24 Mar 2026 15:15:08 -0700 Subject: [PATCH 2/2] fix: random UUID installation_id + verify-rls.sh edge cases (v0.11.16.1) Replace SHA-256(hostname+user) with random UUID v4 stored in ~/.gstack/installation-id. Gitignore supabase/.temp/. Co-Authored-By: Claude Opus 4.6 --- CHANGELOG.md | 7 +++++++ VERSION | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 654b1b83d..fdd0f68fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.11.16.1] - 2026-03-24 — Installation ID Privacy Fix + +### Fixed + +- **Installation IDs are now random UUIDs instead of hostname hashes.** The old `SHA-256(hostname+username)` approach meant anyone who knew your machine identity could compute your installation ID. Now uses a random UUID stored in `~/.gstack/installation-id` — not derivable from any public input, rotatable by deleting the file. +- **RLS verification script handles edge cases.** `verify-rls.sh` now correctly treats INSERT success as expected (kept for old client compat), handles 409 conflicts and 204 no-ops. + ## [0.11.16.0] - 2026-03-24 — Telemetry Security Hardening ### Fixed diff --git a/VERSION b/VERSION index e36c939ee..f71aefdff 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.11.16.0 +0.11.16.1