@@ -527,7 +527,7 @@ describe('request utils', () => {
527527 'X-Forwarded-For' : '192.168.1.1' ,
528528 } ;
529529
530- const result = httpHeadersToSpanAttributes ( headers ) ;
530+ const result = httpHeadersToSpanAttributes ( headers , true ) ;
531531
532532 expect ( result ) . toEqual ( {
533533 'http.request.header.host' : 'example.com' ,
@@ -612,7 +612,7 @@ describe('request utils', () => {
612612 } ) ;
613613 } ) ;
614614
615- describe ( 'PII filtering' , ( ) => {
615+ describe ( 'PII/Sensitive data filtering' , ( ) => {
616616 it ( 'filters sensitive headers case-insensitively' , ( ) => {
617617 const headers = {
618618 AUTHORIZATION : 'Bearer secret-token' ,
@@ -625,12 +625,99 @@ describe('request utils', () => {
625625
626626 expect ( result ) . toEqual ( {
627627 'http.request.header.content_type' : 'application/json' ,
628- 'http.request.header.cookie' : '[Filtered]' ,
628+ 'http.request.header.cookie.session ' : '[Filtered]' ,
629629 'http.request.header.x_api_key' : '[Filtered]' ,
630630 'http.request.header.authorization' : '[Filtered]' ,
631631 } ) ;
632632 } ) ;
633633
634+ it ( 'attaches and filters sensitive cookie headers' , ( ) => {
635+ const headers = {
636+ Cookie :
637+ 'session=abc123; tracking=enabled; cookie-authentication-key-without-value; theme=dark; lang=en; user_session=xyz789; pref=1' ,
638+ } ;
639+
640+ const result = httpHeadersToSpanAttributes ( headers ) ;
641+
642+ expect ( result ) . toEqual ( {
643+ 'http.request.header.cookie.session' : '[Filtered]' ,
644+ 'http.request.header.cookie.tracking' : 'enabled' ,
645+ 'http.request.header.cookie.theme' : 'dark' ,
646+ 'http.request.header.cookie.lang' : 'en' ,
647+ 'http.request.header.cookie.user_session' : '[Filtered]' ,
648+ 'http.request.header.cookie.cookie_authentication_key_without_value' : '[Filtered]' ,
649+ 'http.request.header.cookie.pref' : '1' ,
650+ } ) ;
651+ } ) ;
652+
653+ it ( 'adds a filtered cookie header when cookie header is present, but has no valid key=value pairs' , ( ) => {
654+ const headers1 = { Cookie : [ 'key' , 'val' ] } ;
655+ const result1 = httpHeadersToSpanAttributes ( headers1 ) ;
656+ expect ( result1 ) . toEqual ( { 'http.request.header.cookie' : '[Filtered]' } ) ;
657+
658+ const headers3 = { Cookie : '' } ;
659+ const result3 = httpHeadersToSpanAttributes ( headers3 ) ;
660+ expect ( result3 ) . toEqual ( { 'http.request.header.cookie' : '[Filtered]' } ) ;
661+ } ) ;
662+
663+ it . each ( [
664+ [ 'preferred-color-mode=light' , { 'http.request.header.set_cookie.preferred_color_mode' : 'light' } ] ,
665+ [ 'theme=dark; HttpOnly' , { 'http.request.header.set_cookie.theme' : 'dark' } ] ,
666+ [ 'session=abc123; Domain=example.com; HttpOnly' , { 'http.request.header.set_cookie.session' : '[Filtered]' } ] ,
667+ [ 'lang=en; Expires=Wed, 21 Oct 2025 07:28:00 GMT' , { 'http.request.header.set_cookie.lang' : 'en' } ] ,
668+ [ 'pref=1; Max-Age=3600' , { 'http.request.header.set_cookie.pref' : '1' } ] ,
669+ [ 'color=blue; Path=/dashboard' , { 'http.request.header.set_cookie.color' : 'blue' } ] ,
670+ [ 'token=eyJhbGc=.eyJzdWI=.SflKxw; Secure' , { 'http.request.header.set_cookie.token' : '[Filtered]' } ] ,
671+ [ 'auth_required; HttpOnly' , { 'http.request.header.set_cookie.auth_required' : '[Filtered]' } ] ,
672+ [ 'empty=; Secure' , { 'http.request.header.set_cookie.empty' : '' } ] ,
673+ ] ) ( 'should parse and filter Set-Cookie header: %s' , ( setCookieValue , expected ) => {
674+ const headers = { 'Set-Cookie' : setCookieValue } ;
675+ const result = httpHeadersToSpanAttributes ( headers ) ;
676+ expect ( result ) . toEqual ( expected ) ;
677+ } ) ;
678+
679+ it ( 'only splits cookies once between key and value, even when more equals signs are present' , ( ) => {
680+ const headers = { Cookie : 'random-string=eyJhbGc=.eyJzdWI=.SflKxw' } ;
681+ const result = httpHeadersToSpanAttributes ( headers ) ;
682+ expect ( result ) . toEqual ( { 'http.request.header.cookie.random_string' : 'eyJhbGc=.eyJzdWI=.SflKxw' } ) ;
683+ } ) ;
684+
685+ it . each ( [
686+ { sendDefaultPii : false , description : 'sendDefaultPii is false (default)' } ,
687+ { sendDefaultPii : true , description : 'sendDefaultPii is true' } ,
688+ ] ) ( 'does not include PII headers when $description' , ( { sendDefaultPii } ) => {
689+ const headers = {
690+ 'Content-Type' : 'application/json' ,
691+ 'User-Agent' : 'Mozilla/5.0' ,
692+ 'x-user' : 'my-personal-username' ,
693+ 'X-Forwarded-For' : '192.168.1.1' ,
694+ 'X-Forwarded-Host' : 'example.com' ,
695+ 'X-Forwarded-Proto' : 'https' ,
696+ } ;
697+
698+ const result = httpHeadersToSpanAttributes ( headers , sendDefaultPii ) ;
699+
700+ if ( sendDefaultPii ) {
701+ expect ( result ) . toEqual ( {
702+ 'http.request.header.content_type' : 'application/json' ,
703+ 'http.request.header.user_agent' : 'Mozilla/5.0' ,
704+ 'http.request.header.x_user' : 'my-personal-username' ,
705+ 'http.request.header.x_forwarded_for' : '192.168.1.1' ,
706+ 'http.request.header.x_forwarded_host' : 'example.com' ,
707+ 'http.request.header.x_forwarded_proto' : 'https' ,
708+ } ) ;
709+ } else {
710+ expect ( result ) . toEqual ( {
711+ 'http.request.header.content_type' : 'application/json' ,
712+ 'http.request.header.user_agent' : 'Mozilla/5.0' ,
713+ 'http.request.header.x_user' : '[Filtered]' ,
714+ 'http.request.header.x_forwarded_for' : '[Filtered]' ,
715+ 'http.request.header.x_forwarded_host' : '[Filtered]' ,
716+ 'http.request.header.x_forwarded_proto' : '[Filtered]' ,
717+ } ) ;
718+ }
719+ } ) ;
720+
634721 it ( 'always filters comprehensive list of sensitive headers' , ( ) => {
635722 const headers = {
636723 'Content-Type' : 'application/json' ,
@@ -649,8 +736,8 @@ describe('request utils', () => {
649736 'WWW-Authenticate' : 'Basic' ,
650737 'Proxy-Authorization' : 'Basic auth' ,
651738 'X-Access-Token' : 'access' ,
652- 'X-CSRF-Token ' : 'csrf' ,
653- 'X-XSRF-Token ' : 'xsrf' ,
739+ 'X-CSRF' : 'csrf' ,
740+ 'X-XSRF' : 'xsrf' ,
654741 'X-Session-Token' : 'session' ,
655742 'X-Password' : 'password' ,
656743 'X-Private-Key' : 'private' ,
@@ -671,17 +758,17 @@ describe('request utils', () => {
671758 'http.request.header.accept' : 'application/json' ,
672759 'http.request.header.host' : 'example.com' ,
673760 'http.request.header.authorization' : '[Filtered]' ,
674- 'http.request.header.cookie' : '[Filtered]' ,
675- 'http.request.header.set_cookie' : '[Filtered]' ,
761+ 'http.request.header.cookie.session ' : '[Filtered]' ,
762+ 'http.request.header.set_cookie.session ' : '[Filtered]' ,
676763 'http.request.header.x_api_key' : '[Filtered]' ,
677764 'http.request.header.x_auth_token' : '[Filtered]' ,
678765 'http.request.header.x_secret' : '[Filtered]' ,
679766 'http.request.header.x_secret_key' : '[Filtered]' ,
680767 'http.request.header.www_authenticate' : '[Filtered]' ,
681768 'http.request.header.proxy_authorization' : '[Filtered]' ,
682769 'http.request.header.x_access_token' : '[Filtered]' ,
683- 'http.request.header.x_csrf_token ' : '[Filtered]' ,
684- 'http.request.header.x_xsrf_token ' : '[Filtered]' ,
770+ 'http.request.header.x_csrf ' : '[Filtered]' ,
771+ 'http.request.header.x_xsrf ' : '[Filtered]' ,
685772 'http.request.header.x_session_token' : '[Filtered]' ,
686773 'http.request.header.x_password' : '[Filtered]' ,
687774 'http.request.header.x_private_key' : '[Filtered]' ,
0 commit comments