import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { hardenCredentialFile } from '../server/standalone/key-setup-hardening.mjs'; const FILE = path.join(os.tmpdir(), 'provider-settings-test'); const USER_SID = 'S-1-5-21-1111111111-2222222222-3333333333-1001'; const WINDOWS_ROOT = 'C:\\Windows'; function windowsFileSystem({ root = WINDOWS_ROOT, systemDirectory = 'System32', realpaths = {}, missing = [], symlinks = [], } = {}) { const tools = [ `${root}\\${systemDirectory}\\whoami.exe`, `${root}\\${systemDirectory}\\icacls.exe`, `${root}\\${systemDirectory}\\WindowsPowerShell\\v1.0\\powershell.exe`, ]; const realpathSync = (filepath) => realpaths[filepath] || filepath; realpathSync.native = realpathSync; return { realpathSync, lstatSync(filepath) { return { isDirectory: () => filepath === root, isFile: () => tools.includes(filepath) && !missing.includes(filepath), isSymbolicLink: () => symlinks.includes(filepath), }; }, }; } function fileSystemWithMode(mode = 0o600) { const calls = []; return { calls, chmodSync(filepath, nextMode) { calls.push(['chmod', filepath, nextMode]); }, statSync(filepath) { calls.push(['stat', filepath]); return { mode }; }, }; } test('macOS ACL removal failure stops before chmod and fails closed', () => { const fileSystem = fileSystemWithMode(); const result = hardenCredentialFile(FILE, { platform: 'darwin', fileSystem, spawn: () => ({ status: 1, signal: null }), }); assert.equal(result, false); assert.deepEqual(fileSystem.calls, [], 'mode bits must not disguise an ACL-removal failure'); }); test('macOS ACL removal spawns Apple /bin/chmod by absolute path, not via PATH', () => { const spawned = []; hardenCredentialFile(FILE, { platform: 'darwin', fileSystem: fileSystemWithMode(0o100600), spawn(command, args) { spawned.push([command, args]); return { status: 0, signal: null }; }, }); // A coreutils-first PATH (Nix home-manager, Homebrew) resolves bare `chmod` // to GNU chmod, which has no `-N` and would fail every save. assert.deepEqual(spawned, [['/bin/chmod', ['-N', FILE]]]); }); test('POSIX hardening verifies the resulting 0600 mode', () => { const goodFs = fileSystemWithMode(0o100600); assert.equal(hardenCredentialFile(FILE, { platform: 'darwin', fileSystem: goodFs, spawn: () => ({ status: 0, signal: null }), }), true); assert.deepEqual(goodFs.calls, [['chmod', FILE, 0o600], ['stat', FILE]]); const broadFs = fileSystemWithMode(0o100640); assert.equal(hardenCredentialFile(FILE, { platform: 'linux', fileSystem: broadFs, spawn: () => { throw new Error('Linux must not spawn chmod'); }, }), false); }); test('Windows hardening refuses an unstructured or broad owner SID before icacls', () => { const commands = []; const result = hardenCredentialFile('C:\\GEV\\ENVIRONMENT.tmp', { platform: 'win32', environment: { SYSTEMROOT: WINDOWS_ROOT }, fileSystem: windowsFileSystem(), spawn(command) { commands.push(command); return { status: 0, signal: null, stdout: '"S-1-5-21-1-2-3-1001","S-1-5-32-545"' }; }, }); assert.equal(result, false); assert.deepEqual(commands, [`${WINDOWS_ROOT}\\System32\\whoami.exe`]); }); test('Windows hardening applies and then verifies the exact restricted DACL', () => { const calls = []; const filepath = 'C:\\GEV App\\pinokio\\ENVIRONMENT.tmp'; const result = hardenCredentialFile(filepath, { platform: 'win32', environment: { SYSTEMROOT: WINDOWS_ROOT }, fileSystem: windowsFileSystem(), spawn(command, args, options) { calls.push({ command, args, options }); if (command.endsWith('\\whoami.exe')) { return { status: 0, signal: null, stdout: `"WORKSTATION\\alice","${USER_SID}"\r\n` }; } return { status: 0, signal: null }; }, }); assert.equal(result, true); assert.deepEqual(calls.map(({ command }) => command), [ `${WINDOWS_ROOT}\\System32\\whoami.exe`, `${WINDOWS_ROOT}\\System32\\icacls.exe`, `${WINDOWS_ROOT}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`, ]); assert.deepEqual(calls[1].args, [ filepath, '/inheritance:r', '/grant:r', `*${USER_SID}:F`, '*S-1-5-18:F', '*S-1-5-32-544:F', ]); assert.equal(calls[1].args.filter((arg) => arg === '/grant:r').length, 1); assert.equal(calls[2].options.env.GEV_ACL_FILE, filepath); assert.equal(calls[2].options.env.GEV_ACL_USER_SID, USER_SID); assert.match(calls[2].args.at(-1), /AreAccessRulesProtected/); assert.match(calls[2].args.at(-1), /rules\.Count -ne 3/); assert.match(calls[2].args.at(-1), /seen\.ContainsKey/); assert.match(calls[2].args.at(-1), /FileSystemRights -ne \$full/); assert.match(calls[2].args.at(-1), /seen\.Count -ne 3/); }); test('Windows hardening isolates the verify PowerShell from a pwsh7-polluted PSModulePath', () => { const calls = []; // Exactly what a side-by-side PowerShell 7 install prepends at startup: // its own user Documents\PowerShell, Program Files\PowerShell, and // Program Files\PowerShell\7 module trees all shadow the 5.1 system path. const pollutedModulePath = [ 'C:\\Users\\alice\\Documents\\PowerShell\\Modules', 'C:\\Program Files\\PowerShell\\Modules', 'c:\\program files\\powershell\\7\\Modules', 'C:\\Program Files\\WindowsPowerShell\\Modules', 'C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules', ].join(';'); const result = hardenCredentialFile('C:\\GEV\\ENVIRONMENT.tmp', { platform: 'win32', environment: { SYSTEMROOT: WINDOWS_ROOT, PSModulePath: pollutedModulePath, }, fileSystem: windowsFileSystem(), spawn(command, args, options) { calls.push({ command, args, options }); if (command.endsWith('\\whoami.exe')) { return { status: 0, signal: null, stdout: `"WORKSTATION\\alice","${USER_SID}"\r\n` }; } return { status: 0, signal: null }; }, }); assert.equal(result, true); const verify = calls.find(({ command }) => command.endsWith('powershell.exe')); assert.ok(verify, 'the ACL verify powershell must be spawned'); const modulePath = verify.options.env.PSModulePath; // Fail closed: the verification interpreter must never inherit pwsh7's // module trees — a 7.x Microsoft.PowerShell.Security manifest cannot be // autoloaded by 5.1, and an untrusted tree must not shadow Get-Acl at all. assert.ok(!/Documents\\PowerShell\\Modules/i.test(modulePath), 'user pwsh7 module tree must be stripped'); assert.ok(!/Program Files\\PowerShell\\Modules/i.test(modulePath), 'Program Files pwsh7 module tree must be stripped'); assert.ok(!/Program Files\\PowerShell\\7\\Modules/i.test(modulePath), 'pwsh7 install module tree must be stripped'); // ... but the 5.1 system module directory (where Get-Acl lives) must remain. assert.match(modulePath, /System32\\WindowsPowerShell\\v1\.0\\Modules/i); }); test('the verify script takes its module path from the running interpreter', () => { const calls = []; const result = hardenCredentialFile('C:\\GEV\\ENVIRONMENT.tmp', { platform: 'win32', environment: { SYSTEMROOT: WINDOWS_ROOT }, fileSystem: windowsFileSystem(), spawn(command, args, options) { calls.push({ command, args, options }); if (command.endsWith('\\whoami.exe')) { return { status: 0, signal: null, stdout: `"WORKSTATION\\alice","${USER_SID}"` }; } return { status: 0, signal: null }; }, }); assert.equal(result, true); const verify = calls.find(({ command }) => command.endsWith('powershell.exe')); const script = verify.args.at(-1); // $PSHOME is the interpreter's own physical directory, so this holds even // where the executable was named through a bridge path. assert.match(script, /\$env:PSModulePath = Join-Path \$PSHOME 'Modules'/); // ...and it is the first thing the script does, before Get-Acl is resolved. assert.ok( script.indexOf('PSModulePath') < script.indexOf('Get-Acl'), 'the module path must be set before Get-Acl is invoked', ); }); test('a 32-bit caller passes the physical module directory, not the Sysnative bridge', () => { const calls = []; const result = hardenCredentialFile('C:\\GEV\\ENVIRONMENT.tmp', { platform: 'win32', architecture: 'ia32', environment: { SYSTEMROOT: WINDOWS_ROOT }, fileSystem: windowsFileSystem({ systemDirectory: 'Sysnative' }), spawn(command, args, options) { calls.push({ command, args, options }); if (command.endsWith('\\whoami.exe')) { return { status: 0, signal: null, stdout: `"WORKSTATION\\alice","${USER_SID}"` }; } return { status: 0, signal: null }; }, }); assert.equal(result, true); const verify = calls.find(({ command }) => command.endsWith('powershell.exe')); // The executable is still named through the bridge the 32-bit caller needs. assert.match(verify.command, /\\Sysnative\\/); // The module directory is not: Sysnative is not a directory the launched // native process can read. assert.doesNotMatch(verify.options.env.PSModulePath, /Sysnative/i); assert.match( verify.options.env.PSModulePath, /^C:\\Windows\\System32\\WindowsPowerShell\\v1\.0\\Modules$/i, ); }); test('differently cased PSModulePath aliases do not survive into the verify process', () => { const calls = []; const result = hardenCredentialFile('C:\\GEV\\ENVIRONMENT.tmp', { platform: 'win32', environment: { SYSTEMROOT: WINDOWS_ROOT, // Windows environment names are case-insensitive; a child can keep a // differently cased alias alongside the value set for it. PSMODULEPATH: 'C:\\Program Files\\PowerShell\\7\\Modules', psmodulepath: 'C:\\Users\\alice\\Documents\\PowerShell\\Modules', PsModulePath: 'C:\\attacker\\Modules', }, fileSystem: windowsFileSystem(), spawn(command, args, options) { calls.push({ command, args, options }); if (command.endsWith('\\whoami.exe')) { return { status: 0, signal: null, stdout: `"WORKSTATION\\alice","${USER_SID}"` }; } return { status: 0, signal: null }; }, }); assert.equal(result, true); const verify = calls.find(({ command }) => command.endsWith('powershell.exe')); const aliases = Object.keys(verify.options.env).filter( (name) => name.toLowerCase() === 'psmodulepath', ); assert.deepEqual(aliases, ['PSModulePath'], 'exactly one spelling may reach the child'); assert.doesNotMatch(verify.options.env.PSModulePath, /PowerShell\\7|Documents|attacker/i); }); test('Windows hardening bypasses PATH-shadowed native ACL tools', () => { const commands = []; const result = hardenCredentialFile('D:\\GEV\\ENVIRONMENT.tmp', { platform: 'win32', environment: { PATH: 'D:\\pinokio\\bin;C:\\Windows\\System32', SystemRoot: WINDOWS_ROOT, WINDIR: 'c:\\windows\\', }, fileSystem: windowsFileSystem(), spawn(command) { commands.push(command); if (command.endsWith('\\whoami.exe')) { return { status: 0, signal: null, stdout: `"WORKSTATION\\alice","${USER_SID}"` }; } return { status: 0, signal: null }; }, }); assert.equal(result, true); assert.equal(commands.some((command) => !command.startsWith(`${WINDOWS_ROOT}\\System32\\`)), false); }); test('Windows hardening rejects redirected or ambiguous system roots before spawning', () => { const rejected = [ {}, { SYSTEMROOT: 'Windows' }, { SYSTEMROOT: '\\Windows' }, { SYSTEMROOT: '\\\\server\\share\\Windows' }, { SYSTEMROOT: '\\\\?\\C:\\Windows' }, { SYSTEMROOT: 'C:\\Temp\\..\\Windows' }, { SYSTEMROOT: 'C:\\attacker\\Windows' }, { SYSTEMROOT: WINDOWS_ROOT, WINDIR: 'D:\\Windows' }, ]; for (const environment of rejected) { let spawned = false; const result = hardenCredentialFile('C:\\GEV\\ENVIRONMENT.tmp', { platform: 'win32', environment, fileSystem: windowsFileSystem(), spawn() { spawned = true; return { status: 0, signal: null }; }, }); assert.equal(result, false, JSON.stringify(environment)); assert.equal(spawned, false, JSON.stringify(environment)); } }); test('Windows hardening accepts a canonical Windows root on a non-default drive', () => { const root = 'D:\\Windows'; const commands = []; const result = hardenCredentialFile('D:\\GEV\\ENVIRONMENT.tmp', { platform: 'win32', environment: { SYSTEMROOT: root }, fileSystem: windowsFileSystem({ root }), spawn(command) { commands.push(command); if (command.endsWith('\\whoami.exe')) { return { status: 0, signal: null, stdout: `"WORKSTATION\\alice","${USER_SID}"` }; } return { status: 0, signal: null }; }, }); assert.equal(result, true); assert.equal(commands.every((command) => command.startsWith('D:\\Windows\\System32\\')), true); }); test('32-bit Windows hardening uses the native Sysnative bridge', () => { const commands = []; const result = hardenCredentialFile('C:\\GEV\\ENVIRONMENT.tmp', { platform: 'win32', architecture: 'ia32', environment: { SYSTEMROOT: WINDOWS_ROOT }, fileSystem: windowsFileSystem({ systemDirectory: 'Sysnative' }), spawn(command) { commands.push(command); if (command.endsWith('\\whoami.exe')) { return { status: 0, signal: null, stdout: `"WORKSTATION\\alice","${USER_SID}"` }; } return { status: 0, signal: null }; }, }); assert.equal(result, true); assert.equal(commands.every((command) => command.includes('\\Sysnative\\')), true); }); test('Windows hardening rejects missing, redirected, or non-file native tools', () => { const whoami = `${WINDOWS_ROOT}\\System32\\whoami.exe`; const cases = [ windowsFileSystem({ missing: [whoami] }), windowsFileSystem({ realpaths: { [WINDOWS_ROOT]: 'C:\\RedirectedWindows' } }), windowsFileSystem({ realpaths: { [whoami]: 'C:\\attacker\\whoami.exe' } }), windowsFileSystem({ realpaths: { [whoami]: 'C:\\Windows\\Temp\\evil-whoami.exe' } }), windowsFileSystem({ symlinks: [whoami] }), ]; for (const fileSystem of cases) { let spawned = false; assert.equal(hardenCredentialFile('C:\\GEV\\ENVIRONMENT.tmp', { platform: 'win32', environment: { SYSTEMROOT: WINDOWS_ROOT }, fileSystem, spawn() { spawned = true; return { status: 0, signal: null }; }, }), false); assert.equal(spawned, false); } }); test('Windows hardening fails closed when ACL application or verification fails', () => { for (const failingCommand of ['icacls.exe', 'powershell.exe']) { const calls = []; const result = hardenCredentialFile('C:\\GEV\\ENVIRONMENT.tmp', { platform: 'win32', environment: { SYSTEMROOT: WINDOWS_ROOT }, fileSystem: windowsFileSystem(), spawn(command) { calls.push(command); if (command.endsWith('\\whoami.exe')) { return { status: 0, signal: null, stdout: `"WORKSTATION\\alice","${USER_SID}"` }; } return { status: command.endsWith(`\\${failingCommand}`) ? 1 : 0, signal: null }; }, }); assert.equal(result, false, `${failingCommand} failure must refuse the write`); assert.equal(calls.at(-1).endsWith(`\\${failingCommand}`), true); } }); test('Windows hardening converts subprocess exceptions into a fail-closed result', () => { assert.equal(hardenCredentialFile('C:\\GEV\\ENVIRONMENT.tmp', { platform: 'win32', environment: { SYSTEMROOT: WINDOWS_ROOT }, fileSystem: windowsFileSystem(), spawn() { throw new Error('subprocess unavailable'); }, }), false); }); test('Windows production hardener applies its exact DACL with native tools', { skip: process.platform !== 'win32', }, () => { const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'gev-provider-acl-')); const filepath = path.join(directory, 'ENVIRONMENT.tmp'); try { fs.writeFileSync(filepath, ''); assert.equal(hardenCredentialFile(filepath), true); } finally { fs.rmSync(directory, { recursive: true, force: true }); } });