fix(core): remove filesystem binding for secret storage stability

Removes Inode and Birthtime from the Master Key derivation shards.
These identifiers were too volatile for atomic write operations (which change inodes) and did not survive extension re-installs or file moves.

Master Key security remains extremely high, relying on:
- OS Keychain Shard (Tier 1)
- Physical Shard (~/.gemini_id) (Tier 2)
- Deep Hardware Binding (Motherboard, Disk, MAC) (Tier 3)
- Cryptographic Pepper (Tier 4)
This commit is contained in:
galz10
2026-02-24 13:33:06 -08:00
parent 50c7195528
commit 161ba76f65
2 changed files with 6 additions and 16 deletions
@@ -21,10 +21,10 @@ vi.mock('node:fs', () => {
mkdir: vi.fn(),
rename: vi.fn(),
},
statsSync: vi.fn((_p: string) => ({
ino: 12345,
birthtimeMs: 67890,
})),
statSync: vi.fn(() => ({
ino: 12345,
birthtimeMs: 67890,
})),
};
});
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { promises as fs, statSync } from 'node:fs';
import { promises as fs } from 'node:fs';
import * as path from 'node:path';
import * as os from 'node:os';
import * as crypto from 'node:crypto';
@@ -193,16 +193,6 @@ export class FileSecretStorage implements SecretStorage {
const userSecret = process.env['GEMINI_MASTER_KEY'] || '';
let fsBinding = '';
if (version === 'v2') {
try {
const stats = statSync(this.secretFilePath);
fsBinding = `${stats.ino}-${stats.birthtimeMs}`;
} catch {
// File doesn't exist yet
}
}
let systemSecret = '';
if (version === 'v2') {
systemSecret = (await this.getPersistentSystemSecret()) || '';
@@ -217,7 +207,7 @@ export class FileSecretStorage implements SecretStorage {
const password =
version === 'v2'
? `${FileSecretStorage.PEPPER}-v2-${this.serviceName}-${machineIdentifier}-${fsBinding}-${systemSecret}-${installationId}-${userSecret}`
? `${FileSecretStorage.PEPPER}-v3-${this.serviceName}-${machineIdentifier}-${systemSecret}-${installationId}-${userSecret}`
: `gemini-cli-secret-v1-${this.serviceName}-${userSecret}`;
let salt: Buffer;