Skip to content

fix(proxy): Correct hop-by-hop header handling per RFC 9110#4459

Merged
yusukebe merged 8 commits intohonojs:mainfrom
sugar-cat7:chore/proxy-remove-hop-by-headers
Oct 16, 2025
Merged

fix(proxy): Correct hop-by-hop header handling per RFC 9110#4459
yusukebe merged 8 commits intohonojs:mainfrom
sugar-cat7:chore/proxy-remove-hop-by-headers

Conversation

@sugar-cat7
Copy link
Copy Markdown
Contributor

@sugar-cat7 sugar-cat7 commented Oct 14, 2025

The code references RFC 2616, which has been obsoleted by RFC 7230 (2014) and then RFC 9110 (2022).

Fixed hop-by-hop headers list

  • Changed 'trailers' to 'trailer' in hopByHopHeaders array
    • RFC 2616 originally listed "Trailers" but this was an error, corrected in RFC 2616 Errata ID 4522 (Status: Verified)
    • Subsequent RFCs (7230, 9110) use Trailer (singular)
  • Added missing 'upgrade' header

Verified Connection header parsing

  • RFC 9110 Section 7.6.1:

    Intermediaries MUST parse a received Connection header field before a message is forwarded and, for each connection-option in this field, remove any header or trailer field(s) from the message with the same name as the connection-option

  • Add tests

  • Run tests

  • bun run format:fix && bun run lint:fix to format the code

  • Add TSDoc/JSDoc to document the code

@codecov
Copy link
Copy Markdown

codecov Bot commented Oct 14, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.33%. Comparing base (4b796cf) to head (ea37348).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4459      +/-   ##
==========================================
+ Coverage   91.32%   91.33%   +0.01%     
==========================================
  Files         173      173              
  Lines       11084    11107      +23     
  Branches     3201     3209       +8     
==========================================
+ Hits        10122    10145      +23     
  Misses        961      961              
  Partials        1        1              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Member

@usualoma usualoma left a comment

Choose a reason for hiding this comment

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

Verified Connection header parsing

Thank you for pointing that out! I wasn't aware of that specification.

However, if headers like the following can be specified in the connection value and deleted, it seems this could lead to issues classified as "Hop-by-Hop Header Injection".

  • X-Forwarded-For
  • X-Real-IP

While it's desirable to have functionality that respects the "Connection" header, I feel it should only be enabled explicitly as an option.

Comment thread src/helper/proxy/index.ts Outdated
@sugar-cat7 sugar-cat7 force-pushed the chore/proxy-remove-hop-by-headers branch 2 times, most recently from a30e2a0 to 941d00b Compare October 15, 2025 10:57
@sugar-cat7
Copy link
Copy Markdown
Contributor Author

sugar-cat7 commented Oct 15, 2025

Verified Connection header parsing

Thank you for pointing that out! I wasn't aware of that specification.

However, if headers like the following can be specified in the connection value and deleted, it seems this could lead to issues classified as "Hop-by-Hop Header Injection".

  • X-Forwarded-For
  • X-Real-IP

While it's desirable to have functionality that respects the "Connection" header, I feel it should only be enabled explicitly as an option.

Thank you for pointing this out! You're absolutely right about the Hop-by-Hop Header Injection risk.

I've added a strictConnectionProcessing option (default: false):

  • Default behavior: Ignores the Connection header entirely to prevent injection attacks
  • Strict mode (true): Processes Connection header per RFC 9110 (use only in trusted environments)

@sugar-cat7 sugar-cat7 force-pushed the chore/proxy-remove-hop-by-headers branch from 941d00b to c4a278c Compare October 15, 2025 11:04
@sugar-cat7 sugar-cat7 requested a review from usualoma October 15, 2025 11:08
Copy link
Copy Markdown
Member

@usualoma usualoma left a comment

Choose a reason for hiding this comment

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

Hi @sugar-cat7, thanks for your help.
I believe strictConnectionProcessing should be fine!

Sorry, just one more thing when you have time.

When strictConnectionProcessing is enabled, the following request results in an "Internal Server Error". Since this option is mainly used in trusted environments, we generally don't need to worry about invalid values. However, configuration errors could still cause problems. In those cases, I think we should either return a 400 error or just ignore it.

$ curl -H 'connection: a a' http://localhost:3000/internal-proxy/x

@sugar-cat7
Copy link
Copy Markdown
Contributor Author

Hi @sugar-cat7, thanks for your help. I believe strictConnectionProcessing should be fine!

Sorry, just one more thing when you have time.

When strictConnectionProcessing is enabled, the following request results in an "Internal Server Error". Since this option is mainly used in trusted environments, we generally don't need to worry about invalid values. However, configuration errors could still cause problems. In those cases, I think we should either return a 400 error or just ignore it.

$ curl -H 'connection: a a' http://localhost:3000/internal-proxy/x

@usualoma
Thank you for pointing this out!

  • Added header (token) validation based on RFC 9110 Section 5.6.2, returning 400 on validation failure.

@sugar-cat7 sugar-cat7 force-pushed the chore/proxy-remove-hop-by-headers branch from b8eb419 to ee4ed17 Compare October 15, 2025 18:35
@sugar-cat7 sugar-cat7 requested a review from usualoma October 15, 2025 18:38
Copy link
Copy Markdown
Member

@usualoma usualoma left a comment

Choose a reason for hiding this comment

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

I've left a comment, so please check it!

Comment thread src/helper/proxy/index.ts Outdated

const result = processConnectionHeader(raw, strictConnectionProcessing)
if (!result.isSuccess) {
return new Response(result.message, { status: 400 })
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry for not explaining earlier, but I want to throw an HTTPException.

throw new HTTPException(400, { message })

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Changed to throw an error.

throw new HTTPException(400, {

Comment thread src/helper/proxy/index.ts Outdated
...requestInit
} = proxyInit instanceof Request ? { raw: proxyInit } : proxyInit ?? {}

const result = processConnectionHeader(raw, strictConnectionProcessing)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The variable name “result” seems to be a temporary variable used to hold the function's "result," so I believe it should be renamed.

Copy link
Copy Markdown
Contributor Author

@sugar-cat7 sugar-cat7 Oct 16, 2025

Choose a reason for hiding this comment

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

Reverted to initial implementation and consolidated logic into buildRequestInitFromRequest since errors are now thrown.
ea37348

@sugar-cat7 sugar-cat7 requested a review from usualoma October 16, 2025 21:01
Copy link
Copy Markdown
Member

@usualoma usualoma left a comment

Choose a reason for hiding this comment

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

Thank you. I think it’s a great improvement!

Copy link
Copy Markdown
Member

@yusukebe yusukebe left a comment

Choose a reason for hiding this comment

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

LGTM!

@yusukebe
Copy link
Copy Markdown
Member

@sugar-cat7 @usualoma

Thanks! Merging and releasing a new version (it's a minor bump!).

@yusukebe yusukebe merged commit 9ae98c9 into honojs:main Oct 16, 2025
20 checks passed
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.

3 participants