mirror of
https://github.com/storytold/craft-launcher.git
synced 2026-11-02 18:07:04 +00:00
security: bypass proxy for loopback and suppress HTTP wire credential logging (F-003, F-005)
This commit is contained in:
@@ -119,6 +119,21 @@ impl Sink {
|
||||
}
|
||||
}
|
||||
|
||||
/// Suppresses sensitive authorization tokens in log output (CWE-532).
|
||||
pub(crate) fn redact_credentials(text: &str) -> String {
|
||||
let mut result = String::with_capacity(text.len());
|
||||
let mut remaining = text;
|
||||
while let Some(idx) = remaining.to_ascii_lowercase().find("bearer ") {
|
||||
result.push_str(&remaining[..idx + 7]);
|
||||
let token_rest = &remaining[idx + 7..];
|
||||
let end_token = token_rest.find(|c: char| c.is_whitespace() || c == '"' || c == '\'' || c == '\r' || c == '\n').unwrap_or(token_rest.len());
|
||||
result.push_str("[REDACTED]");
|
||||
remaining = &token_rest[end_token..];
|
||||
}
|
||||
result.push_str(remaining);
|
||||
result
|
||||
}
|
||||
|
||||
/// env_logger's output: each formatted record to standard error and to the [`Sink`].
|
||||
struct Tee {
|
||||
sink: Arc<Mutex<Sink>>,
|
||||
@@ -127,10 +142,12 @@ struct Tee {
|
||||
|
||||
impl Write for Tee {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
let text = String::from_utf8_lossy(buf);
|
||||
let sanitized = redact_credentials(&text);
|
||||
if self.stderr {
|
||||
let _ = std::io::stderr().write_all(buf);
|
||||
let _ = std::io::stderr().write_all(sanitized.as_bytes());
|
||||
}
|
||||
self.sink.lock().unwrap_or_else(PoisonError::into_inner).write(&String::from_utf8_lossy(buf));
|
||||
self.sink.lock().unwrap_or_else(PoisonError::into_inner).write(&sanitized);
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
@@ -164,6 +181,8 @@ impl Logs {
|
||||
/// An env_logger builder (filter from `RUST_LOG`, else [`DEFAULT_FILTER`]) writing through a [`Tee`].
|
||||
fn builder(sink: Arc<Mutex<Sink>>, stderr: bool) -> env_logger::Builder {
|
||||
let mut b = env_logger::Builder::from_env(env_logger::Env::default().default_filter_or(DEFAULT_FILTER));
|
||||
// Suppress raw HTTP wire TRACE records before formatting and output, regardless of RUST_LOG (CWE-532).
|
||||
b.filter_module("ureq_proto", log::LevelFilter::Debug);
|
||||
b.target(env_logger::Target::Pipe(Box::new(Tee { sink, stderr })));
|
||||
b
|
||||
}
|
||||
@@ -329,4 +348,11 @@ mod tests {
|
||||
assert!(read(&path).contains("after the panic\n"));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn redact_credentials_replaces_bearer_tokens() {
|
||||
assert_eq!(redact_credentials("Authorization: Bearer ghp_secretToken1234567890"), "Authorization: Bearer [REDACTED]");
|
||||
assert_eq!(redact_credentials("header \"authorization: bearer my_secret\" and more"), "header \"authorization: bearer [REDACTED]\" and more");
|
||||
assert_eq!(redact_credentials("normal log line without tokens"), "normal log line without tokens");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user