@@ -81,9 +81,11 @@ describe('createSessionToken / verifySessionToken', () => {
8181 TEST_SECRET ,
8282 ) ;
8383
84- // Flip the last character of the signature (third segment)
84+ // Flip the first character of the signature — the first char encodes 6 full
85+ // data bits, so any change reliably alters the decoded value (unlike the last
86+ // char, which only carries 4 data bits and can be a no-op when those bits collide).
8587 const parts = token . split ( '.' ) ;
86- parts [ 2 ] = parts [ 2 ] . slice ( 0 , - 1 ) + ( parts [ 2 ] . endsWith ( 'a' ) ? 'b' : 'a' ) ;
88+ parts [ 2 ] = ( parts [ 2 ] [ 0 ] === 'a' ? 'b' : 'a' ) + parts [ 2 ] . slice ( 1 ) ;
8789 const tampered = parts . join ( '.' ) ;
8890
8991 await expect ( verifySessionToken ( tampered , TEST_SECRET ) ) . rejects . toThrow ( ) ;
@@ -146,7 +148,9 @@ describe('createTempSessionToken / verifyTempSessionToken', () => {
146148 it ( 'rejects a tampered temp token' , async ( ) => {
147149 const token = await createTempSessionToken ( 'temp-sess-3' , TEST_SECRET ) ;
148150 const parts = token . split ( '.' ) ;
149- parts [ 2 ] = parts [ 2 ] . slice ( 0 , - 1 ) + ( parts [ 2 ] . endsWith ( 'a' ) ? 'b' : 'a' ) ;
151+ // Flip the first character of the signature — reliably changes the decoded
152+ // value regardless of which character the signature happens to end with.
153+ parts [ 2 ] = ( parts [ 2 ] [ 0 ] === 'a' ? 'b' : 'a' ) + parts [ 2 ] . slice ( 1 ) ;
150154
151155 await expect ( verifyTempSessionToken ( parts . join ( '.' ) , TEST_SECRET ) ) . rejects . toThrow ( ) ;
152156 } ) ;
0 commit comments