#510·PairDrop

cf-connecting-ip is trusted unconditionally, allowing cross-network IP-room join via a spoofed header

Author: carfeiiCreated Sep 11, 2026Updated Sep 11, 2026

Summary

PairDrop groups peers that share a public IP into an "IP room" for automatic device discovery and file transfer. The server derives that IP in Peer._setIP (server/peer.js), checking cf-connecting-ip first and trusting it unconditionally, then x-forwarded-for, then the socket address. On any instance not behind Cloudflare, cf-connecting-ip is an ordinary client-supplied request header, so a remote client can send cf-connecting-ip: <victim's public IP> on the WebSocket upgrade and be placed in an arbitrary victim's IP room.

Affected version: confirmed on commit 1b0c9c9 (v1.11.2, current master).

Details

server/peer.js _setIP uses cf-connecting-ip as the first-choice source for this.ip, which is the room key for IP-based auto-discovery (_joinIpRoom -> _joinRoom(peer, 'ip', peer.ip) in server/ws-server.js). There is no configuration gating which client-IP headers are trusted; the only proxy setting (conf.rateLimit) is applied solely to express-rate-limit, not to the WebSocket peer-IP derivation.

The documented reverse-proxy deployment (docs/host-your-own.md) uses proxy_set_header X-Forwarded-for $remote_addr;, which overwrites X-Forwarded-For with the connecting client address and closes the XFF vector, but it does not touch cf-connecting-ip. Because _setIP checks cf-connecting-ip first, a client behind that exact documented setup can still supply its own cf-connecting-ip and have it used as the room key. Only an instance that sits behind Cloudflare (which sets and strips this header) is safe, and PairDrop currently has no way to express whether it is behind Cloudflare.

POC

(available upon request)

Impact

A remote user of a PairDrop instance who knows or guesses a victim's public IP can join that victim's IP auto-discovery room by sending a spoofed cf-connecting-ip header, defeating the "same network only" boundary for IP rooms. The attacker then appears to the victim as a local-network device and can solicit file transfers (which the victim may accept, believing the peer is local) and observe the victim's advertised device name and type. With WS_FALLBACK enabled, transferred data is relayed through the server. This affects instances not behind Cloudflare, including the documented nginx reverse-proxy deployment.

A fix PR gating cf-connecting-ip behind an opt-in CF_CONNECTING_IP option (default off) is attached.