fix: validate CCS Bar launch shim target integrity (#1626)

* fix: validate CCS Bar launch shim target integrity

* fix: execute verified bar shim bytes
This commit is contained in:
Kai (Tam Nhu) Tran authored and GitHub committed 2026-07-01 00:49:56 -04:00
1 parent 05685d1c21
commit 3621f8dcb1
2 files changed
+78 -3

No files matched your search

+24 -1
View File
@@ -8,6 +8,7 @@
* instead of the package-manager entrypoint.
*/
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
@@ -17,6 +18,10 @@ import type { LaunchJson } from './bar-paths';
const SHIM_MODE = 0o700;
function sha256File(filePath: string): string {
return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex');
}
export interface LaunchDescriptorOptions {
entrypointPath?: string;
runtime?: string;
@@ -38,11 +43,29 @@ function resolveEntrypoint(entrypointPath?: string): string {
export function writeLaunchShim(home: string, entrypointPath?: string): string {
const resolvedEntrypoint = resolveEntrypoint(entrypointPath);
const expectedEntrypointHash = sha256File(resolvedEntrypoint);
const shimPath = getLaunchShimPath(home);
const shimDir = path.dirname(shimPath);
const contents = [
'#!/usr/bin/env node',
`require(${JSON.stringify(resolvedEntrypoint)});`,
"const crypto = require('crypto');",
"const fs = require('fs');",
"const Module = require('module');",
"const path = require('path');",
`const expectedEntrypoint = ${JSON.stringify(resolvedEntrypoint)};`,
`const expectedHash = ${JSON.stringify(expectedEntrypointHash)};`,
'const resolvedEntrypoint = fs.realpathSync(expectedEntrypoint);',
"if (resolvedEntrypoint !== expectedEntrypoint) throw new Error('CCS Bar launch shim target changed. Run `ccs bar launch` to refresh launch.json.');",
'const entrypointStat = fs.statSync(resolvedEntrypoint);',
"if (!entrypointStat.isFile()) throw new Error('CCS Bar launch shim target is not a regular file.');",
'const source = fs.readFileSync(resolvedEntrypoint);',
"const actualHash = crypto.createHash('sha256').update(source).digest('hex');",
"if (actualHash !== expectedHash) throw new Error('CCS Bar launch shim target changed. Run `ccs bar launch` to refresh launch.json.');",
'const targetModule = new Module(resolvedEntrypoint, module);',
'targetModule.filename = resolvedEntrypoint;',
'targetModule.paths = Module._nodeModulePaths(path.dirname(resolvedEntrypoint));',
'require.cache[resolvedEntrypoint] = targetModule;',
"targetModule._compile(source.toString('utf8'), resolvedEntrypoint);",
'',
].join('\n');
@@ -805,9 +805,61 @@ describe('launch descriptor shim', () => {
const mode = fs.statSync(descriptor.args[0]).mode & 0o777;
expect((mode & 0o022) === 0).toBe(true);
const resolvedEntrypoint = fs.realpathSync(realEntrypoint);
expect(fs.readFileSync(descriptor.args[0], 'utf8')).toContain(
`require(${JSON.stringify(resolvedEntrypoint)});`
const shimContents = fs.readFileSync(descriptor.args[0], 'utf8');
expect(shimContents).toContain(
`const expectedEntrypoint = ${JSON.stringify(resolvedEntrypoint)};`
);
expect(shimContents).toContain('const expectedHash = ');
expect(shimContents).toContain('const source = fs.readFileSync(resolvedEntrypoint);');
expect(shimContents).toContain('if (actualHash !== expectedHash)');
expect(shimContents).toContain('require.cache[resolvedEntrypoint] = targetModule;');
expect(shimContents).toContain(
"targetModule._compile(source.toString('utf8'), resolvedEntrypoint);"
);
expect(shimContents).not.toContain('require(resolvedEntrypoint);');
});
it('rejects a modified original entrypoint before executing it', async () => {
const packageDist = path.join(
tempHome,
'.bun',
'install',
'global',
'node_modules',
'@kaitranntt',
'ccs',
'dist'
);
const binDir = path.join(tempHome, '.bun', 'bin');
const markerPath = path.join(tempHome, 'attacker-marker');
const realEntrypoint = path.join(packageDist, 'ccs.js');
const symlinkedEntrypoint = path.join(binDir, 'ccs');
fs.mkdirSync(packageDist, { recursive: true });
fs.mkdirSync(binDir, { recursive: true });
fs.writeFileSync(realEntrypoint, 'console.log("original");\n', { mode: 0o777 });
fs.symlinkSync(realEntrypoint, symlinkedEntrypoint);
const { createBarLaunchDescriptor } = await loadLaunchDescriptor();
const descriptor = createBarLaunchDescriptor({
entrypointPath: symlinkedEntrypoint,
runtime: process.execPath,
home: tempHome,
});
fs.writeFileSync(
realEntrypoint,
`require('fs').writeFileSync(${JSON.stringify(markerPath)}, 'executed');\n`
);
const proc = Bun.spawnSync([descriptor.runtime, ...descriptor.args], {
stdout: 'pipe',
stderr: 'pipe',
});
expect(proc.exitCode).not.toBe(0);
expect(Buffer.from(proc.stderr).toString()).toContain('CCS Bar launch shim target changed');
expect(fs.existsSync(markerPath)).toBe(false);
});
});