91 lines
2.8 KiB
Markdown
91 lines
2.8 KiB
Markdown
# UNDF: UNDF-2026-000001153
|
||
# root-cern-0002 — TWebFile HTTP Authorization header logged verbatim (CWE-312) MOAD-0004
|
||
|
||
## Target
|
||
ROOT (CERN data analysis framework) — https://github.com/root-project/root
|
||
|
||
## File
|
||
`net/net/src/TWebFile.cxx`
|
||
|
||
## CWE
|
||
CWE-312: Cleartext Storage of Sensitive Information
|
||
|
||
## Location
|
||
`TWebFile::GetFromWeb10()`, lines 716–717:
|
||
|
||
```cpp
|
||
if (gDebug > 0)
|
||
Info("GetFromWeb10", "sending HTTP request:\n%s", msg.Data());
|
||
```
|
||
|
||
`msg` is `fMsgReadBuffer10`, which is assembled by `SetMsgReadBuffer10()` at line 348:
|
||
|
||
```cpp
|
||
fMsgReadBuffer10 += BasicAuthentication();
|
||
```
|
||
|
||
`BasicAuthentication()` (lines 1375–1389) constructs:
|
||
|
||
```
|
||
Authorization: Basic <base64(username:password)>\r\n
|
||
```
|
||
|
||
When `gDebug > 0` (set by `gDebug = 1` in ROOT macros/scripts — a common debugging
|
||
practice), the full HTTP GET request including the `Authorization: Basic` header is
|
||
printed verbatim to stderr/stdout via `Info()`.
|
||
|
||
base64 is not encryption. Decoding `Authorization: Basic dXNlcjpwYXNzd29yZA==`
|
||
immediately reveals `user:password`.
|
||
|
||
## Also Affected
|
||
`TS3WebFile` inherits from `TWebFile` and overrides `SetMsgReadBuffer10()` to set:
|
||
|
||
```cpp
|
||
fMsgReadBuffer10 = fS3Request.GetRequest(TS3HTTPRequest::kGET, kFALSE) + "Range: bytes=";
|
||
```
|
||
|
||
`TS3HTTPRequest::GetRequest()` includes an `Authorization: AWS <AccessKey>:<Signature>`
|
||
header computed from our secret access key. This signature and access key are also
|
||
logged verbatim when `gDebug > 0`.
|
||
|
||
## Credential Types Exposed
|
||
1. HTTP Basic Auth: `username:password` (base64-encoded, trivially reversible)
|
||
2. S3/AWS: `AccessKey:HMAC-SHA1(SecretKey, request)` — exposes access key and allows
|
||
signature forgery until key rotation
|
||
|
||
## Trigger Condition
|
||
`gDebug > 0` — a single-line change in any ROOT script:
|
||
```
|
||
gDebug = 1;
|
||
```
|
||
This is commonly set for debugging slow data access, which is exactly the scenario
|
||
where TWebFile is used (remote files over HTTP/S3).
|
||
|
||
## Fix
|
||
Redact the Authorization header before logging:
|
||
|
||
```cpp
|
||
if (gDebug > 0) {
|
||
TString logMsg = msg;
|
||
// Redact Authorization header before logging
|
||
Ssiz_t authPos = logMsg.Index("Authorization:", 0, TString::kIgnoreCase);
|
||
if (authPos != kNPOS) {
|
||
Ssiz_t eol = logMsg.Index("\r\n", authPos);
|
||
if (eol != kNPOS)
|
||
logMsg.Replace(authPos, eol - authPos, "Authorization: [REDACTED]");
|
||
}
|
||
Info("GetFromWeb10", "sending HTTP request:\n%s", logMsg.Data());
|
||
}
|
||
```
|
||
|
||
Or alternatively, never log the Authorization line at this debug level; use
|
||
`gDebug > 3` for full header logging with a clear security disclaimer.
|
||
|
||
## Severity
|
||
HIGH — affects any ROOT user who enables debug output while accessing password-protected
|
||
or S3-backed ROOT files. ROOT's primary use case is CERN physics data stored on
|
||
remote storage (XROOTD, HTTP, S3). Setting `gDebug = 1` to diagnose slow access
|
||
is the first thing any physicist would do.
|
||
|
||
## Date
|
||
2026-03-31
|