[GH-ISSUE #2787] Sensitive Credentials Logged in Plaintext #1299

Closed
opened 2026-03-04 01:52:55 +03:00 by kerem · 7 comments
Owner

Originally created by @CarstenGrohmann on GitHub (Jan 21, 2026).
Original GitHub issue: https://github.com/s3fs-fuse/s3fs-fuse/issues/2787

Summary

Multiple locations in the codebase log sensitive credentials (IAM tokens, secret keys, SSE-C encryption keys) in plaintext. This exposes credentials in log files, syslog, and potentially centralized logging systems.

Affected Code

1. IMDSv2 API Token logged on set (INFO3 level)

github.com/s3fs-fuse/s3fs-fuse@4eee60ac2f/src/s3fs_cred.cpp (L410)

2. Full IAM Credential Response logged (INFO3 level)

Contains AccessKeyId, SecretAccessKey, Token, and Expiration in plaintext:

github.com/s3fs-fuse/s3fs-fuse@4eee60ac2f/src/s3fs_cred.cpp (L505-L507)

3. IMDSv2 Token logged on error (ERR level - always output!)

github.com/s3fs-fuse/s3fs-fuse@4eee60ac2f/src/s3fs_cred.cpp (L383)

4. IAM Token logged in request function (INFO3 level)

github.com/s3fs-fuse/s3fs-fuse@4eee60ac2f/src/s3fs_threadreqs.cpp (L1481)

5. IAM Token AND IBM Secret Access Key logged (INFO3 level)

github.com/s3fs-fuse/s3fs-fuse@4eee60ac2f/src/s3fs_threadreqs.cpp (L1497)

6. SSE-C Encryption Key logged on error (ERR level - always output!)

github.com/s3fs-fuse/s3fs-fuse@4eee60ac2f/src/curl.cpp (L651)

Risk Assessment

Location Log Macro When Output
s3fs_cred.cpp:410 S3FS_PRN_INFO3 -o dbglevel=info3 or higher
s3fs_cred.cpp:507 S3FS_PRN_INFO3 -o dbglevel=info3 or higher
s3fs_cred.cpp:383 S3FS_PRN_ERR Always
s3fs_threadreqs.cpp:1481 S3FS_PRN_INFO3 -o dbglevel=info3 or higher
s3fs_threadreqs.cpp:1497 S3FS_PRN_INFO3 -o dbglevel=info3 or higher
curl.cpp:651 S3FS_PRN_ERR Always

Attack Vectors

  1. Log files: /var/log/syslog, systemd journal, custom log files
  2. Log aggregation: Splunk, ELK, CloudWatch Logs
  3. Shared hosting: Other users with read access to logs
  4. Backup systems: Logs in backups contain credentials
  5. Support requests: Users send debug logs to developers

Suggested Fix

Use masked output showing only first/last character and length. This enables troubleshooting while protecting credentials:

std::string mask_secret(const std::string& secret) {
      if(secret.empty()) {
          return std::string("(empty)");
      }
      if(secret.length() <= 5) {
          return std::string("***");
      }
      return std::string(1, secret[0]) + "..." +
             std::string(1, secret[secret.length()-1]) +
             " (len=" + std::to_string(secret.length()) + ")";
}

Example output:

  • AKIAIOSFODNN7EXAMPLE → A...E (len=20)
  • wJalrXUtnFEMI/K7MDENG → w...G (len=21)
  • Session Token (~1000 chars) → A...= (len=1024)

Additionally, consider changing log level from S3FS_PRN_INFO3 to S3FS_PRN_DBG for credential-related debug output.

Originally created by @CarstenGrohmann on GitHub (Jan 21, 2026). Original GitHub issue: https://github.com/s3fs-fuse/s3fs-fuse/issues/2787 # Summary Multiple locations in the codebase log sensitive credentials (IAM tokens, secret keys, SSE-C encryption keys) in plaintext. This exposes credentials in log files, syslog, and potentially centralized logging systems. # Affected Code ## 1. IMDSv2 API Token logged on set (INFO3 level) https://github.com/s3fs-fuse/s3fs-fuse/blob/4eee60ac2f45c33ab1ba58856f04e83c4e5a76a8/src/s3fs_cred.cpp#L410 ## 2. Full IAM Credential Response logged (INFO3 level) Contains AccessKeyId, SecretAccessKey, Token, and Expiration in plaintext: https://github.com/s3fs-fuse/s3fs-fuse/blob/4eee60ac2f45c33ab1ba58856f04e83c4e5a76a8/src/s3fs_cred.cpp#L505-L507 ## 3. IMDSv2 Token logged on error (ERR level - always output!) https://github.com/s3fs-fuse/s3fs-fuse/blob/4eee60ac2f45c33ab1ba58856f04e83c4e5a76a8/src/s3fs_cred.cpp#L383 ## 4. IAM Token logged in request function (INFO3 level) https://github.com/s3fs-fuse/s3fs-fuse/blob/4eee60ac2f45c33ab1ba58856f04e83c4e5a76a8/src/s3fs_threadreqs.cpp#L1481 ## 5. IAM Token AND IBM Secret Access Key logged (INFO3 level) https://github.com/s3fs-fuse/s3fs-fuse/blob/4eee60ac2f45c33ab1ba58856f04e83c4e5a76a8/src/s3fs_threadreqs.cpp#L1497 ## 6. SSE-C Encryption Key logged on error (ERR level - always output!) https://github.com/s3fs-fuse/s3fs-fuse/blob/4eee60ac2f45c33ab1ba58856f04e83c4e5a76a8/src/curl.cpp#L651 # Risk Assessment | Location | Log Macro | When Output | |-----------|-----------|-------------| | s3fs_cred.cpp:410 | `S3FS_PRN_INFO3` | `-o dbglevel=info3` or higher | | s3fs_cred.cpp:507 | `S3FS_PRN_INFO3` | `-o dbglevel=info3` or higher | | s3fs_cred.cpp:383 | `S3FS_PRN_ERR` | Always | | s3fs_threadreqs.cpp:1481 | `S3FS_PRN_INFO3` | `-o dbglevel=info3` or higher | | s3fs_threadreqs.cpp:1497 | `S3FS_PRN_INFO3` | `-o dbglevel=info3` or higher | | curl.cpp:651 | `S3FS_PRN_ERR` | Always | # Attack Vectors 1. Log files: `/var/log/syslog`, systemd journal, custom log files 2. Log aggregation: Splunk, ELK, CloudWatch Logs 3. Shared hosting: Other users with read access to logs 4. Backup systems: Logs in backups contain credentials 5. Support requests: Users send debug logs to developers # Suggested Fix Use masked output showing only first/last character and length. This enables troubleshooting while protecting credentials: ```cpp std::string mask_secret(const std::string& secret) { if(secret.empty()) { return std::string("(empty)"); } if(secret.length() <= 5) { return std::string("***"); } return std::string(1, secret[0]) + "..." + std::string(1, secret[secret.length()-1]) + " (len=" + std::to_string(secret.length()) + ")"; } ``` Example output: - AKIAIOSFODNN7EXAMPLE → A...E (len=20) - wJalrXUtnFEMI/K7MDENG → w...G (len=21) - Session Token (~1000 chars) → A...= (len=1024) Additionally, consider changing log level from S3FS_PRN_INFO3 to S3FS_PRN_DBG for credential-related debug output.
kerem closed this issue 2026-03-04 01:52:55 +03:00
Author
Owner

@ggtakec commented on GitHub (Jan 23, 2026):

@CarstenGrohmann Thanks for reporting this issue.
This issue is not good, so I will fix it tomorrow and make a PR.

I appreciate the meaningful code you suggested, but I would also like to avoid printing the token's head(tail) character and length.
Since all user need is information about token problem that prevented authentication, I believe it would be wise not to output any information about the token itself.(so, the current code is even worse.)
Even if not including any token information in the message affects troubleshooting(such as taking longer to parse), I would prefer not outputting the information.

<!-- gh-comment-id:3790278791 --> @ggtakec commented on GitHub (Jan 23, 2026): @CarstenGrohmann Thanks for reporting this issue. This issue is not good, so I will fix it tomorrow and make a PR. I appreciate the meaningful code you suggested, but I would also like to avoid printing the token's head(tail) character and length. Since all user need is information about token problem that prevented authentication, I believe it would be wise not to output any information about the token itself.(so, the current code is even worse.) Even if not including any token information in the message affects troubleshooting(such as taking longer to parse), I would prefer not outputting the information.
Author
Owner

@CarstenGrohmann commented on GitHub (Jan 23, 2026):

@ggtakec I have probably found other similar issues. Do you prefer security-related issues to be reported via GH issues/PRs, or do you prefer a different channel for such reports?

<!-- gh-comment-id:3792241696 --> @CarstenGrohmann commented on GitHub (Jan 23, 2026): @ggtakec I have probably found other similar issues. Do you prefer security-related issues to be reported via GH issues/PRs, or do you prefer a different channel for such reports?
Author
Owner

@ggtakec commented on GitHub (Jan 24, 2026):

@CarstenGrohmann I think it would be best to report it via GH Issue/PR.
If there are any issues that you are hesitant to report, I would appreciate it if you could contact me individually(@gaul and me).

And based on this issue, I am also checking the output locations of authentication and authorization tokens and credentials.

<!-- gh-comment-id:3793774202 --> @ggtakec commented on GitHub (Jan 24, 2026): @CarstenGrohmann I think it would be best to report it via GH Issue/PR. If there are any issues that you are hesitant to report, I would appreciate it if you could contact me individually(@gaul and me). And based on this issue, I am also checking the output locations of authentication and authorization tokens and credentials.
Author
Owner

@ggtakec commented on GitHub (Jan 24, 2026):

@CarstenGrohmann
I have posted #2792 and look forward to your review.

I have masked the sensitive information in the log you pointed out, and more(curldbg option's log).
The function you provided displayed part of the tokens(and credentials) and its length, but I have changed it so that this information is not output.

I have also added a new insecure_logging option, which allows the same logs to be output as before.
This allows developers to use this option for debugging when necessary. (I have also added it to the s3fs-fsue CI test script.)

Thanks in advance for your help.

<!-- gh-comment-id:3795065910 --> @ggtakec commented on GitHub (Jan 24, 2026): @CarstenGrohmann I have posted #2792 and look forward to your review. I have masked the sensitive information in the log you pointed out, and more(curldbg option's log). The function you provided displayed part of the tokens(and credentials) and its length, but I have changed it so that this information is not output. I have also added a new `insecure_logging` option, which allows the same logs to be output as before. This allows developers to use this option for debugging when necessary. (I have also added it to the s3fs-fsue CI test script.) Thanks in advance for your help.
Author
Owner

@CarstenGrohmann commented on GitHub (Jan 24, 2026):

@ggtakec
Thank you, for your fast PR.

There is a second place where credentials are logged: print_launch_message() (e.g. parameters -o ssl_client_cert="<SSL Cert>:...:<Password>" or -o url=https://access_key:secret_key@s3.amazonaws.com). A similar solution would be good for these.

<!-- gh-comment-id:3795527194 --> @CarstenGrohmann commented on GitHub (Jan 24, 2026): @ggtakec Thank you, for your fast PR. There is a second place where credentials are logged: `print_launch_message()` (e.g. parameters `-o ssl_client_cert="<SSL Cert>:...:<Password>"` or `-o url=https://access_key:secret_key@s3.amazonaws.com`). A similar solution would be good for these.
Author
Owner

@ggtakec commented on GitHub (Jan 25, 2026):

@CarstenGrohmann I've added masking to the messages output by print_launch_message, made other fixes, and updated the PR code.
Please review updated code.

<!-- gh-comment-id:3796350760 --> @ggtakec commented on GitHub (Jan 25, 2026): @CarstenGrohmann I've added masking to the messages output by print_launch_message, made other fixes, and updated the PR code. Please review updated code.
Author
Owner

@CarstenGrohmann commented on GitHub (Feb 7, 2026):

Fixed in #2792

<!-- gh-comment-id:3863739034 --> @CarstenGrohmann commented on GitHub (Feb 7, 2026): Fixed in #2792
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/s3fs-fuse#1299
No description provided.