Conversation
Accept "loopback" for server.trustProxy so Express only honors X-Forwarded-For hops appended by a proxy on the same machine (cloudflared or a local reverse proxy). With `true`, any client can pick its own req.ip, which also keys the OAuth endpoints' rate limiting. In loopback mode request logs use the IP Express resolves instead of reading forwarding headers directly, so logs and rate limiting agree.
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (1)
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review. 📝 WalkthroughWalkthroughThe ChangesProxy trust configuration and IP handling
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix Sequence Diagram(s)sequenceDiagram
participant Client
participant Express
participant requestIp
Client->>Express: Send request with forwarded hops
Express->>Express: Resolve req.ip using trustProxy
Express->>requestIp: Pass request and trustProxy mode
requestIp->>requestIp: Read forwarding headers only when trustProxy is true
requestIp-->>Express: Return resolved IP
Merge Risk: ⚪ Minimal · up to The new mode is carried consistently from configuration to Express and request logging. The reviewed changes show no concrete issue that should block merging. Security Architecture ReviewSecurity architecture risk: 🟡 Moderate · up to The new mode can distinguish callers behind a local tunnel without trusting every forwarded address. Its protection depends on the local proxy supplying a trustworthy client address, which the configuration does not enforce and the documentation does not spell out. Retained concerns
Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. A rabbit checks the forwarded trail, Comment |
|
| const { port } = server.address() as AddressInfo; | ||
| // The client supplies the leftmost hop; the local proxy appends the real peer. | ||
| const response = await fetch(`http://127.0.0.1:${port}/`, { | ||
| headers: { "x-forwarded-for": "198.51.100.66, 203.0.113.7" }, |
There was a problem hiding this comment.
The loopback test sends only X-Forwarded-For, so it still passes if logging begins preferring a client-supplied CF-Connecting-IP over Express’s trusted req.ip. That leaves a logging regression undetected. Send a conflicting CF header and assert that the logged IP remains req.ip. This test-coverage concern does not block merging.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Artifacts
Executed test and mutation command
- This script creates isolated source copies, applies the loopback-only mutation, and runs the unchanged tests and HTTP probe against each copy, showing the exact executed setup.
Source of the spoofed-header HTTP request
- This executed probe sends both forwarding headers and captures the HTTP response and request-log IP, showing how the mismatch was measured.
Original code: passing tests and matching IPs
- The unchanged test passed 3/3 and the HTTP 200 OK request logged the same IP as req.ip, establishing the baseline.
Mutated code: passing tests despite spoofed logged IP
- The unchanged test still passed 3/3, while the HTTP 200 OK request logged the spoofed CF IP instead of req.ip, confirming the coverage gap.
Comments Outside DiffThese findings sit on lines the diff does not cover, so they could not be posted inline. Each one leaves this list once its file changes.
|
|
Following up on the automated reviews:
|
When DevSpace runs behind a tunnel on the same machine (cloudflared, Tailscale Funnel, a local nginx), every request reaches Express from 127.0.0.1 and the real client address only exists in
X-Forwarded-For.server.trustProxycurrently offers two choices, and neither works well for that setup. Withfalse, every client shares onereq.ip, so the rate limiter on the OAuth endpoints puts all callers in one bucket and anyone can exhaust the owner's/authorizebudget. Withtrue, Express takes the leftmostX-Forwarded-Forentry, which the client controls, so sending a new value per request bypasses the limit on owner password attempts.This adds
"loopback"as a third value forserver.trustProxyand passes it straight to Express'strust proxysetting. Express then trusts only hops appended by a loopback proxy, soreq.ipresolves to the address the tunnel actually saw. Request logs use that samereq.ipin loopback mode instead of readingcf-connecting-iporX-Forwarded-Fordirectly, so logs and rate limiting agree.trueandfalsebehave exactly as before, and the config schema, generated JSON schema, and configuration docs are updated.The new
logger.test.tssends a spoofed leftmost hop through a real Express app in each mode, andconfig.test.tscovers accepting"loopback"and rejecting other strings.Summary by CodeRabbit
falseignores forwarding headers, whiletruetrusts every hop.