Skip to content

Commit 4cf7873

Browse files
authored
feat(http): log Host/Origin rejections (#826)
1 parent fffe138 commit 4cf7873

1 file changed

Lines changed: 30 additions & 4 deletions

File tree

  • crates/rmcp/src/transport/streamable_http_server

crates/rmcp/src/transport/streamable_http_server/tower.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,13 +330,23 @@ fn bad_request_response(message: &str) -> BoxResponse {
330330

331331
fn parse_host_header(headers: &HeaderMap) -> Result<NormalizedAuthority, BoxResponse> {
332332
let Some(host) = headers.get(http::header::HOST) else {
333+
tracing::warn!("rejected request with missing Host header");
333334
return Err(bad_request_response("Bad Request: missing Host header"));
334335
};
335336

336-
let host = host
337+
let host_str = host
337338
.to_str()
339+
.inspect_err(|_| {
340+
tracing::warn!(host = ?host, "rejected request with non-UTF-8 Host header");
341+
})
338342
.map_err(|_| bad_request_response("Bad Request: Invalid Host header encoding"))?;
339-
let authority = http::uri::Authority::try_from(host)
343+
let authority = http::uri::Authority::try_from(host_str)
344+
.inspect_err(|_| {
345+
tracing::warn!(
346+
host = host_str,
347+
"rejected request with malformed Host header"
348+
);
349+
})
340350
.map_err(|_| bad_request_response("Bad Request: Invalid Host header"))?;
341351
Ok(normalize_authority(authority.host(), authority.port_u16()))
342352
}
@@ -347,6 +357,10 @@ fn validate_dns_rebinding_headers(
347357
) -> Result<(), BoxResponse> {
348358
let host = parse_host_header(headers)?;
349359
if !host_is_allowed(&host, &config.allowed_hosts) {
360+
tracing::warn!(
361+
host = ?host,
362+
"rejected request with disallowed Host header (possible DNS rebinding attempt)",
363+
);
350364
return Err(forbidden_response("Forbidden: Host header is not allowed"));
351365
}
352366
validate_origin_header(headers, &config.allowed_origins)?;
@@ -365,10 +379,22 @@ fn validate_origin_header(
365379
};
366380
let origin_str = origin_header
367381
.to_str()
382+
.inspect_err(|_| {
383+
tracing::warn!(origin = ?origin_header, "rejected request with non-UTF-8 Origin header");
384+
})
368385
.map_err(|_| bad_request_response("Bad Request: Invalid Origin header encoding"))?;
369-
let origin = parse_origin_value(origin_str)
370-
.ok_or_else(|| bad_request_response("Bad Request: Invalid Origin header"))?;
386+
let origin = parse_origin_value(origin_str).ok_or_else(|| {
387+
tracing::warn!(
388+
origin = origin_str,
389+
"rejected request with malformed Origin header",
390+
);
391+
bad_request_response("Bad Request: Invalid Origin header")
392+
})?;
371393
if !origin_is_allowed(&origin, allowed_origins) {
394+
tracing::warn!(
395+
origin = ?origin,
396+
"rejected request with disallowed Origin header (possible cross-origin attack)",
397+
);
372398
return Err(forbidden_response(
373399
"Forbidden: Origin header is not allowed",
374400
));

0 commit comments

Comments
 (0)