@@ -24,7 +24,10 @@ export async function openURLMiddleware(req: IncomingMessage, res: ServerRespons
2424 if ( ! open ) {
2525 try {
2626 // oxlint-disable-next-line import/no-extraneous-dependencies
27- open = require ( 'open' ) ;
27+ const imported = require ( 'open' ) ;
28+ // Handle both CJS (`module.exports = fn`) and ESM default export (`{ default: fn }`)
29+ // oxlint-disable-next-line typescript-eslint(no-unsafe-member-access)
30+ open = typeof imported === 'function' ? imported : imported ?. default ;
2831 } catch ( e ) {
2932 // noop
3033 }
@@ -56,15 +59,17 @@ export async function openURLMiddleware(req: IncomingMessage, res: ServerRespons
5659
5760 if ( ! isTrustedSentryHost ( url ) ) {
5861 // oxlint-disable-next-line no-console
59- console . log ( `${ S } Untrusted host, not opening automatically. Open manually if you trust this URL: ${ url } ` ) ;
62+ console . log (
63+ `${ S } Untrusted host, not opening automatically. Open manually if you trust this URL: ${ sanitizeForLog ( url ) } ` ,
64+ ) ;
6065 res . writeHead ( 200 ) ;
6166 res . end ( ) ;
6267 return ;
6368 }
6469
6570 if ( ! open ) {
6671 // oxlint-disable-next-line no-console
67- console . log ( `${ S } Could not open URL automatically. Open manually: ${ url } ` ) ;
72+ console . log ( `${ S } Could not open URL automatically. Open manually: ${ sanitizeForLog ( url ) } ` ) ;
6873 res . writeHead ( 500 ) ;
6974 res . end ( 'Failed to open URL. The "open" package is not available. Install it or open the URL manually.' ) ;
7075 return ;
@@ -74,18 +79,26 @@ export async function openURLMiddleware(req: IncomingMessage, res: ServerRespons
7479 await open ( url ) ;
7580 } catch ( e ) {
7681 // oxlint-disable-next-line no-console
77- console . log ( `${ S } Failed to open URL automatically. Open manually: ${ url } ` ) ;
82+ console . log ( `${ S } Failed to open URL automatically. Open manually: ${ sanitizeForLog ( url ) } ` ) ;
7883 res . writeHead ( 500 ) ;
7984 res . end ( 'Failed to open URL.' ) ;
8085 return ;
8186 }
8287
8388 // oxlint-disable-next-line no-console
84- console . log ( `${ S } Opened URL: ${ url } ` ) ;
89+ console . log ( `${ S } Opened URL: ${ sanitizeForLog ( url ) } ` ) ;
8590 res . writeHead ( 200 ) ;
8691 res . end ( ) ;
8792}
8893
94+ /**
95+ * Strip control characters to prevent terminal escape sequence injection when logging URLs.
96+ */
97+ function sanitizeForLog ( value : string ) : string {
98+ // oxlint-disable-next-line no-control-regex
99+ return value . replace ( / [ \x00 - \x1f \x7f ] / g, '' ) ;
100+ }
101+
89102function isTrustedSentryHost ( url : string ) : boolean {
90103 try {
91104 const { hostname } = new URL ( url ) ;
0 commit comments