Repository navigation
fix: derive client IP from trusted proxy hops only - #1399
devflora-princess wants to merge 7 commits into
Conversation
|
@devflora-princess Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
|
Thanks for the contribution! We reviewed this PR while merging the open queue and couldn't merge it yet. Here's what needs fixing:
This branch also has merge conflicts with |
…rusted-proxy-hops-only Resolves merge conflicts against CalloraOrg/Callora-Backend@1518ce6 (68 commit(s) behind) so the PR is mergeable.
|
@greatest0fallt1me — thanks for the review. Addressed both points (and the conflicts):
The branch is based on current |
Restores the IP-allowlist middleware (the previous commit had it base64-encoded into a single line), fixes the broken IPv6 regex in clientIp.ts, and wires TRUST_PROXY_HOPS through createAdminIpAllowlist / createGatewayIpAllowlist with a backwards-compatible legacy boolean fallback. Cleans up the trust-boundary documentation.
The branch renamed the configuration-log field from `trustProxy` to the resolved `trustProxyHops` (so a legacy `trustProxy: true` now logs as the equivalent hop count), but the existing assertion in `src/__tests__/ipAllowlist.test.ts` still expected `trustProxy: true`, which made that suite fail. Update the assertion to the new contract: `trustProxyHops: Number.POSITIVE_INFINITY`. No test is removed; the suite passes 44/44 with `npx jest --runInBand src/lib/__tests__/clientIp.test.ts src/__tests__/ipAllowlist.test.ts`.
|
@greatest0fallt1me Thanks — the review points are addressed, and I fixed one regression the branch had introduced:
Verified locally on the updated head with Node 20:
Please re-review. |
Overview
This PR replaces the boolean
TRUST_PROXY_HEADERSbehavior ingetClientIpwith a trusted-hop-count model that selects the client IP from the right side ofX-Forwarded-For, matching Expresstrust proxysemantics. The leftmost XFF entry is fully client-controlled, so the previous behavior allowed spoofing past the admin IP allowlist and per-IP rate limits. The change keeps the default (no trust) behavior of using the socket address, and updates the allowlist middleware and forwarded-header policy doc to reflect the new invariant.Related Issue
Changes
🔒 Trusted-hop client IP resolution
[MODIFY]
src/lib/clientIp.tsgetClientIpnow takes a trusted hop count instead of a boolean.hopspositions from the right ofX-Forwarded-For, so with one trusted hop1.1.1.1, 2.2.2.2yields2.2.2.2.[MODIFY]
src/config/env.ts0(no trust → socket address).[MODIFY]
src/middleware/ipAllowlist.tsgetClientIpso the allowlist decision is made on the trusted-hop-derived IP rather than the spoofable leftmost value.[MODIFY]
FORWARDED_HEADER_POLICY.mdtrust proxyalignment.[MODIFY]
src/lib/__tests__/clientIp.test.tsVerification Results
X-Forwarded-For: 1.1.1.1, 2.2.2.2yields2.2.2.2getClientIpipAllowlistuses the trusted-hop-derived IP0; socket address usedsrc/lib/__tests__/clientIp.test.tsis updatedSecurity and Failure Modes
0hops), behavior matches the pre-existing no-trust path and uses the socket address.0.Non-goals
Closes #1268