Skip to content

fix uhv underscore header sanitization use-after-free path#44086

Open
Achieve3318 wants to merge 1 commit intoenvoyproxy:mainfrom
Achieve3318:fix-44032-uhv-underscore-uaf
Open

fix uhv underscore header sanitization use-after-free path#44086
Achieve3318 wants to merge 1 commit intoenvoyproxy:mainfrom
Achieve3318:fix-44032-uhv-underscore-uaf

Conversation

@Achieve3318
Copy link

Summary

This PR fixes a potential use-after-free path in underscore-header sanitization for Envoy default UHV when headers_with_underscores_action is DROP_HEADER.

In sanitizeHeadersWithUnderscores(), header names were collected as non-owning absl::string_view values and then removed from the same header map. With duplicate underscore headers (for example, x_foo appearing multiple times), removing one header can invalidate storage referenced by later views.

This change stores owning copies of header names (std::string) before mutation, preventing reads from dangling references during removal.

Fixes: #44032

Changes

  • Updated:
    • source/extensions/http/header_validators/envoy_default/header_validator.cc
  • Replaced:
    • std::vector<absl::string_view> with std::vector<std::string>
    • push_back(header_name) with emplace_back(header_name)
  • Added regression tests for duplicate underscore headers:
    • test/extensions/http/header_validators/envoy_default/http1_header_validator_test.cc
    • test/extensions/http/header_validators/envoy_default/http2_header_validator_test.cc

Test Plan

  • Ran:
    • //test/extensions/http/header_validators/envoy_default:http1_header_validator_test
    • //test/extensions/http/header_validators/envoy_default:http2_header_validator_test
  • Both passed locally.

@repokitteh-read-only
Copy link

Hi @Achieve3318, welcome and thank you for your contribution.

We will try to review your Pull Request as quickly as possible.

In the meantime, please take a look at the contribution guidelines if you have not done so already.

🐱

Caused by: #44086 was opened by Achieve3318.

see: more, trace.

@Achieve3318 Achieve3318 force-pushed the fix-44032-uhv-underscore-uaf branch from c30712d to a5a0ba6 Compare March 23, 2026 12:48
@Achieve3318 Achieve3318 requested a deployment to external-contributors March 23, 2026 12:48 — with GitHub Actions Waiting
@Achieve3318
Copy link
Author

hi, @paul-r-gall Please review my PR

Comment on lines +637 to +644
// Store owning copies because removing one duplicate header can free the
// underlying storage for another matching entry.
std::vector<std::string> drop_headers;
header_map.iterate([&drop_headers](const ::Envoy::Http::HeaderEntry& header_entry)
-> ::Envoy::Http::HeaderMap::Iterate {
const absl::string_view header_name = header_entry.key().getStringView();
if (absl::StrContains(header_name, '_')) {
drop_headers.push_back(header_name);
drop_headers.emplace_back(header_name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than keep a copy, could we keep header name in a absl::flat_hash_set?

@wbpcode wbpcode assigned yanavlasov and wbpcode and unassigned yanavlasov Mar 25, 2026
@wbpcode
Copy link
Member

wbpcode commented Mar 25, 2026

/wait

@Achieve3318 Achieve3318 force-pushed the fix-44032-uhv-underscore-uaf branch from a5a0ba6 to 18b230a Compare March 25, 2026 13:16
@Achieve3318
Copy link
Author

@wbpcode Please review my PR again. Thank your for your review

Comment on lines +638 to +645
// Store owning copies because removing one duplicate header can free the
// underlying storage for another matching entry. We only need unique names.
absl::flat_hash_set<std::string> drop_headers;
header_map.iterate([&drop_headers](const ::Envoy::Http::HeaderEntry& header_entry)
-> ::Envoy::Http::HeaderMap::Iterate {
const absl::string_view header_name = header_entry.key().getStringView();
if (absl::StrContains(header_name, '_')) {
drop_headers.push_back(header_name);
drop_headers.emplace(header_name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I may didn't make it clear. I mean use an absl::flat_hash_set<absl::string_view> drop_headers; to keep the header key, then I think it should also could eliminate the use-after-free?

Use owning underscore header names while sanitizing, and keep names unique
via absl::flat_hash_set so duplicate header removals cannot read dangling
views. Add HTTP/1 and HTTP/2 regression coverage for duplicate underscore
header names.

Signed-off-by: Achieve3318 <daniel98518@gmail.com>
@Achieve3318 Achieve3318 force-pushed the fix-44032-uhv-underscore-uaf branch from 18b230a to 88a8949 Compare March 25, 2026 13:52
@Achieve3318
Copy link
Author

@wbpcode , Sorry for my mistake. I have fixed again. please check again. Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

uhv: use-after-free read in sanitizeHeadersWithUnderscores with duplicate underscore headers

3 participants