@@ -18,6 +18,7 @@ const getShardedWal = (overrides?: {
1818 format ?: Partial < WalFormat > ;
1919 measureNameEnvVar ?: string ;
2020 autoCoordinator ?: boolean ;
21+ groupId ?: string ;
2122} ) => {
2223 const { format, ...rest } = overrides ?? { } ;
2324 return new ShardedWal ( {
@@ -39,6 +40,9 @@ describe('ShardedWal', () => {
3940 // Clear coordinator env var for fresh state
4041 // eslint-disable-next-line functional/immutable-data, @typescript-eslint/no-dynamic-delete
4142 delete process . env [ PROFILER_SHARDER_ID_ENV_VAR ] ;
43+ // Clear measure name env var to avoid test pollution
44+ // eslint-disable-next-line functional/immutable-data, @typescript-eslint/no-dynamic-delete
45+ delete process . env . CP_PROFILER_MEASURE_NAME ;
4246 } ) ;
4347
4448 describe ( 'initialization' , ( ) => {
@@ -73,6 +77,70 @@ describe('ShardedWal', () => {
7377 } ) ;
7478 } ) ;
7579
80+ describe ( 'path traversal validation' , ( ) => {
81+ it ( 'should reject groupId with forward slashes' , ( ) => {
82+ expect ( ( ) => getShardedWal ( { groupId : '../etc/passwd' } ) ) . toThrow (
83+ 'groupId cannot contain path separators (/ or \\)' ,
84+ ) ;
85+ } ) ;
86+
87+ it ( 'should reject groupId with backward slashes' , ( ) => {
88+ expect ( ( ) => getShardedWal ( { groupId : '..\\windows\\system32' } ) ) . toThrow (
89+ 'groupId cannot contain path separators (/ or \\)' ,
90+ ) ;
91+ } ) ;
92+
93+ it ( 'should reject groupId with parent directory reference' , ( ) => {
94+ expect ( ( ) => getShardedWal ( { groupId : '..' } ) ) . toThrow (
95+ 'groupId cannot be "." or ".."' ,
96+ ) ;
97+ } ) ;
98+
99+ it ( 'should reject groupId with current directory reference' , ( ) => {
100+ expect ( ( ) => getShardedWal ( { groupId : '.' } ) ) . toThrow (
101+ 'groupId cannot be "." or ".."' ,
102+ ) ;
103+ } ) ;
104+
105+ it ( 'should reject groupId with null bytes' , ( ) => {
106+ expect ( ( ) => getShardedWal ( { groupId : 'test\0malicious' } ) ) . toThrow (
107+ 'groupId cannot contain null bytes' ,
108+ ) ;
109+ } ) ;
110+
111+ it ( 'should reject empty groupId' , ( ) => {
112+ expect ( ( ) => getShardedWal ( { groupId : '' } ) ) . toThrow (
113+ 'groupId cannot be empty or whitespace-only' ,
114+ ) ;
115+ } ) ;
116+
117+ it ( 'should reject whitespace-only groupId' , ( ) => {
118+ expect ( ( ) => getShardedWal ( { groupId : ' ' } ) ) . toThrow (
119+ 'groupId cannot be empty or whitespace-only' ,
120+ ) ;
121+ } ) ;
122+
123+ it ( 'should accept safe alphanumeric groupId' , ( ) => {
124+ const sw = getShardedWal ( { groupId : 'safe-group-123' } ) ;
125+ expect ( sw . groupId ) . toBe ( 'safe-group-123' ) ;
126+ } ) ;
127+
128+ it ( 'should accept groupId with underscores and hyphens' , ( ) => {
129+ const sw = getShardedWal ( { groupId : 'test_group-name' } ) ;
130+ expect ( sw . groupId ) . toBe ( 'test_group-name' ) ;
131+ } ) ;
132+
133+ it ( 'should reject groupId from env var with path traversal' , ( ) => {
134+ // eslint-disable-next-line functional/immutable-data
135+ process . env . CP_PROFILER_MEASURE_NAME = '../malicious' ;
136+ expect ( ( ) =>
137+ getShardedWal ( {
138+ measureNameEnvVar : 'CP_PROFILER_MEASURE_NAME' ,
139+ } ) ,
140+ ) . toThrow ( 'groupId cannot contain path separators (/ or \\)' ) ;
141+ } ) ;
142+ } ) ;
143+
76144 describe ( 'shard management' , ( ) => {
77145 it ( 'should create shard with correct file path' , ( ) => {
78146 const sw = getShardedWal ( {
0 commit comments