@@ -122,4 +122,42 @@ echo "4"
122122 const expected = '// a\n// b\n// c\n// d\n// e\n// f'
123123 assert . equal ( transformMarkdown ( input ) , expected )
124124 } )
125+
126+ describe ( 'security: bash fence injection prevention' , ( ) => {
127+ test ( 'escapes ${...} interpolation in bash fences to prevent JS injection' , ( ) => {
128+ const result = transformMarkdown (
129+ '```bash\necho ${require("child_process").execSync("id")}\n```'
130+ )
131+ assert . ok (
132+ result . includes ( '\\${require' ) ,
133+ 'interpolation not escaped in bash fence output'
134+ )
135+ } )
136+
137+ test ( 'escapes backticks in bash fences to prevent template literal breakout' , ( ) => {
138+ const result = transformMarkdown ( '```bash\necho `uname -s`\n```' )
139+ assert . ok (
140+ result . includes ( '\\`uname' ) ,
141+ 'backtick not escaped in bash fence output'
142+ )
143+ } )
144+
145+ test ( 'does not escape ${...} in js fences (intended interpolation)' , ( ) => {
146+ const result = transformMarkdown (
147+ '```js\nconsole.log(`${process.env.HOME}`)\n```'
148+ )
149+ assert . ok (
150+ result . includes ( '${process.env.HOME}' ) ,
151+ 'JS interpolation was incorrectly escaped in js fence'
152+ )
153+ } )
154+
155+ test ( 'bash fence $VAR and $(cmd) pass through unmodified' , ( ) => {
156+ const result = transformMarkdown (
157+ '```bash\necho $HOME\necho $(whoami)\n```'
158+ )
159+ assert . ok ( result . includes ( 'echo $HOME' ) , '$VAR incorrectly modified' )
160+ assert . ok ( result . includes ( 'echo $(whoami)' ) , '$() incorrectly modified' )
161+ } )
162+ } )
125163} )
0 commit comments