@@ -180,4 +180,52 @@ describe("runtime driver specific: node env leakage", () => {
180180 CUSTOM : "value" ,
181181 } ) ;
182182 } ) ;
183+
184+ // ---------------------------------------------------------------
185+ // Env isolation — sandbox mutations must not reach children
186+ // ---------------------------------------------------------------
187+
188+ it ( "sandbox process.env.LD_PRELOAD does not reach child spawned with default env" , async ( ) => {
189+ const { executor, calls } = createCapturingExecutor ( ) ;
190+ proc = createTestNodeRuntime ( {
191+ permissions : { ...allowAllChildProcess , ...allowAllEnv } ,
192+ commandExecutor : executor ,
193+ processConfig : { env : { SAFE_INIT : "yes" } } ,
194+ } ) ;
195+ await proc . run ( `
196+ const cp = require('child_process');
197+ process.env.LD_PRELOAD = '/evil/lib.so';
198+ cp.spawnSync('echo', ['hi']);
199+ ` ) ;
200+ expect ( calls . length ) . toBe ( 1 ) ;
201+ // Child gets init-time env, not the mutated sandbox env
202+ expect ( calls [ 0 ] . env ) . toBeDefined ( ) ;
203+ expect ( calls [ 0 ] . env ! . LD_PRELOAD ) . toBeUndefined ( ) ;
204+ expect ( calls [ 0 ] . env ! . SAFE_INIT ) . toBe ( "yes" ) ;
205+ } ) ;
206+
207+ it ( "sandbox process.env.FOO mutation is visible locally but not in child default env" , async ( ) => {
208+ const { executor, calls } = createCapturingExecutor ( ) ;
209+ const capture = createConsoleCapture ( ) ;
210+ proc = createTestNodeRuntime ( {
211+ permissions : { ...allowAllChildProcess , ...allowAllEnv } ,
212+ commandExecutor : executor ,
213+ processConfig : { env : { INIT_VAR : "original" } } ,
214+ onStdio : capture . onStdio ,
215+ } ) ;
216+ await proc . run ( `
217+ const cp = require('child_process');
218+ process.env.FOO = 'bar';
219+ console.log(JSON.stringify({ foo: process.env.FOO }));
220+ cp.spawnSync('echo', ['hi']);
221+ ` ) ;
222+ // Sandbox-local mutation works
223+ const parsed = JSON . parse ( capture . stdout ( ) . trim ( ) ) ;
224+ expect ( parsed . foo ) . toBe ( "bar" ) ;
225+ // Child gets init-time env without the mutation
226+ expect ( calls . length ) . toBe ( 1 ) ;
227+ expect ( calls [ 0 ] . env ) . toBeDefined ( ) ;
228+ expect ( calls [ 0 ] . env ! . FOO ) . toBeUndefined ( ) ;
229+ expect ( calls [ 0 ] . env ! . INIT_VAR ) . toBe ( "original" ) ;
230+ } ) ;
183231} ) ;
0 commit comments