Skip to content

Sensitive Header Leaks in Error Responses #2117

@cmackenzie1

Description

@cmackenzie1

Apache Iceberg Rust version

0.6.0 (latest version)

Describe the bug

Following the introduction of header logging in #1129, error messages now include a full dump of response headers to assist with debugging.

While helpful for troubleshooting, this current implementation poses a security risk. In environments utilizing specific proxies or middleware, the error logs capture and display sensitive headers, such as Set-Cookie, which contain authentication tokens and session information.

The following is an example log from Arroyo (using iceberg-rs) that demonstrates the issue with Unexpected error variant.

{
  "arroyo_service": "worker",
  "level": "ERROR",
  "fields": {
    "message": "panicked at crates/arroyo-connectors/.../two_phase_committer.rs:175:14: committer initialized: ConnectorError { 
      domain: External, 
      retry: NoRetry, 
      error: \"Unexpected, context: { 
        status: 404 Not Found, 
        headers: {
          \"date\": \"Sat, 31 Jan 2026 09:22:55 GMT\",
          \"content-type\": \"application/json\",
          \"server\": \"cloudflare\",
          \"set-cookie\": \"CF_Authorization=[REDACTED_SENSITIVE_TOKEN]; Path=/; Secure;\", 
          \"x-request-id\": \"3363c133-a05f-493d-a3ab-8b75814c8c3d\"
        }, 
        json: {\"error\":{\"message\":\"Warehouse not found\",\"type\":\"WarehouseNotFound\",\"code\":404}} 
      } => Received response with unexpected status code\", 
      source: None 
    }"
  },
  "pipeline_id": "b00f0dd0..."
}

/// Deserializes a unexpected catalog response into an error.
pub(crate) async fn deserialize_unexpected_catalog_error(response: Response) -> Error {
let err = Error::new(
ErrorKind::Unexpected,
"Received response with unexpected status code",
)
.with_context("status", response.status().to_string())
.with_context("headers", format!("{:?}", response.headers()));
let bytes = match response.bytes().await {
Ok(bytes) => bytes,
Err(err) => return err.into(),
};
if bytes.is_empty() {
return err;
}
err.with_context("json", String::from_utf8_lossy(&bytes))
}

To Reproduce

No response

Expected behavior

Sensitive headers should be redacted or excluded from error strings by default. Users should have the ability to debug headers without exposing PII (Personally Identifiable Information) or credentials in logs.

Suggested Fixes

  • Redaction List: Implement a default deny list for common sensitive headers (e.g., Set-Cookie, Authorization, Proxy-Authorization).
  • Toggleable Logging: Allow users to opt in to full header logging via a configuration flag, keeping it disabled by default for safety.

Willingness to contribute

I would be willing to contribute a fix for this bug with guidance from the Iceberg community

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions