Security is critical when building P2P applications. WebTorrent provides several features to help you protect users, handle untrusted content safely, and maintain privacy. This guide covers security best practices for both Node.js and browser environments.
Privacy Features
Private Torrents
Private torrents prevent DHT and PEX sharing, ensuring peers are only discovered through trackers:
import WebTorrent from 'webtorrent'
const client = new WebTorrent ()
// Torrent files with private flag are automatically handled
client . add ( 'private.torrent' , torrent => {
console . log ( 'Private torrent:' , torrent . private ) // true
// DHT and PEX are automatically disabled
})
// Manually mark a torrent as private
client . add ( magnetURI , {
private: true // disable DHT and PEX
})
Private torrents comply with BEP 27 and are commonly used by private tracker communities to maintain control over their swarms.
IP Blocklists
Block connections from known malicious IPs, copyright trolls, or surveillance entities:
// Node.js only
const client = new WebTorrent ({
blocklist: [
'https://example.com/blocklist.txt' ,
'https://mirror.example.com/blocklist.gz'
]
})
// Or use a local file
const client2 = new WebTorrent ({
blocklist: './path/to/blocklist.txt'
})
// Or provide an array of IPs/ranges
const client3 = new WebTorrent ({
blocklist: [
'1.2.3.4' ,
'10.0.0.0/8' ,
'192.168.0.0/16'
]
})
Blocklists are only available in Node.js environments. Browsers cannot implement IP-level filtering.
Disable Peer Discovery Methods
Selectively disable peer discovery to control how peers are found:
const client = new WebTorrent ({
dht: false , // disable DHT (Node.js only)
tracker: false , // disable all trackers
lsd: false , // disable local service discovery (Node.js)
utPex: false // disable peer exchange
})
Maximum Privacy // Only use approved trackers
const client = new WebTorrent ({
dht: false ,
lsd: false ,
utPex: false
})
client . add ( magnetURI , {
announce: [
'wss://trusted-tracker.example.com'
]
})
Local Network Only // Only find peers on local network
const client = new WebTorrent ({
dht: false ,
tracker: false ,
lsd: true
})
Content Security
Always validate torrent metadata before processing:
client . add ( torrentId , torrent => {
// Validate torrent name for path traversal attacks
if ( torrent . name . includes ( '..' ) || torrent . name . includes ( '/' )) {
console . error ( 'Suspicious torrent name:' , torrent . name )
torrent . destroy ()
return
}
// Validate file names
for ( const file of torrent . files ) {
if ( file . path . includes ( '..' ) || file . path . startsWith ( '/' )) {
console . error ( 'Suspicious file path:' , file . path )
torrent . destroy ()
return
}
}
// Check total size
if ( torrent . length > 10 * 1024 * 1024 * 1024 ) { // 10 GB
console . error ( 'Torrent too large:' , torrent . length )
torrent . destroy ()
return
}
// Torrent is safe to process
console . log ( 'Validated torrent:' , torrent . name )
})
Never trust user-provided torrent IDs or magnet URIs. Always validate metadata after it’s fetched.
File Type Restrictions
Restrict which file types can be downloaded:
const ALLOWED_EXTENSIONS = [ '.mp4' , '.mkv' , '.avi' , '.webm' ]
client . add ( torrentId , torrent => {
// Deselect all files initially
torrent . files . forEach ( file => file . deselect ())
// Only select allowed file types
torrent . files . forEach ( file => {
const ext = file . name . substring ( file . name . lastIndexOf ( '.' ))
if ( ALLOWED_EXTENSIONS . includes ( ext . toLowerCase ())) {
file . select ()
} else {
console . warn ( 'Blocked file type:' , file . name )
}
})
})
Sandboxed File Access
Isolate torrent storage to prevent file system access outside designated areas:
import path from 'path'
import os from 'os'
// Node.js: Use a dedicated download directory
const DOWNLOAD_DIR = path . join ( os . homedir (), 'WebTorrentDownloads' )
const client = new WebTorrent ()
client . add ( torrentId , {
path: DOWNLOAD_DIR ,
addUID: true // add infoHash to path to prevent collisions
})
// Browser: Use File System Access API with user-selected directory
if ( typeof window !== 'undefined' && window . showDirectoryPicker ) {
const dirHandle = await window . showDirectoryPicker ({
mode: 'readwrite'
})
client . add ( torrentId , {
rootDir: dirHandle // scoped to user-selected directory
})
}
Network Security
Secure WebSocket Trackers
Use encrypted WebSocket connections (WSS) for tracker communication:
client . add ( magnetURI , {
announce: [
'wss://tracker.example.com:443/announce' , // secure
// 'ws://tracker.example.com:8000/announce' // avoid unencrypted
]
})
Always prefer WSS over WS for browser applications to prevent mixed content warnings and man-in-the-middle attacks.
WebRTC Security (Browser)
Configure WebRTC for enhanced privacy:
const client = new WebTorrent ({
tracker: {
rtcConfig: {
iceServers: [
// Use your own STUN/TURN servers
{
urls: 'stun:stun.yourdomain.com:3478'
},
{
urls: 'turn:turn.yourdomain.com:3478' ,
username: 'user' ,
credential: 'pass'
}
],
// Prevent IP leaks
iceTransportPolicy: 'relay' // force TURN, no direct connections
}
}
})
Using iceTransportPolicy: 'relay' prevents IP address leaks but requires TURN servers and may reduce performance.
Port Security (Node.js)
Control which ports are used for incoming connections:
const client = new WebTorrent ({
torrentPort: 6881 , // specific port for torrents
dhtPort: 6881 , // specific port for DHT
})
// Or let WebTorrent choose random ports
const client2 = new WebTorrent ({
torrentPort: 0 , // random port
dhtPort: 0 // random port
})
// Disable port mapping to prevent UPnP/NAT-PMP exploits
const client3 = new WebTorrent ({
natUpnp: false ,
natPmp: false
})
When running in Node.js, ensure your firewall allows: Incoming:
TCP on torrentPort (for peer connections)
UDP on dhtPort (for DHT)
Outgoing:
TCP/UDP on all ports (for connecting to peers)
TCP 443 (for HTTPS trackers)
TCP 80 (for HTTP web seeds)
Data Integrity
Piece Verification
WebTorrent automatically verifies each piece using SHA1 hashes from the torrent metadata:
client . add ( torrentId , torrent => {
torrent . on ( 'verify' , ( index ) => {
console . log ( 'Verified piece:' , index )
})
torrent . on ( 'done' , () => {
console . log ( 'All pieces verified!' )
console . log ( 'Hash:' , torrent . infoHash )
})
})
Verification happens automatically. Corrupted pieces are re-downloaded. Never disable verification unless you completely trust the source.
Manual Verification Skip
Skip verification only for trusted, pre-verified data:
// ONLY use with trusted data
client . add ( torrentId , {
skipVerify: true ,
store: preloadedStore // must contain valid, verified data
})
Skipping verification can lead to corrupted downloads. Only use this with data you’ve already verified or trust completely.
Browser-Specific Security
Content Security Policy (CSP)
Configure CSP headers to allow WebRTC while maintaining security:
< meta http-equiv = "Content-Security-Policy"
content = "
default-src 'self';
connect-src 'self' wss: https:;
worker-src 'self' blob:;
script-src 'self' 'wasm-unsafe-eval';
" >
Cross-Origin Isolation
Enable cross-origin isolation for better security:
// Server-side headers (Node.js)
response . setHeader ( 'Cross-Origin-Opener-Policy' , 'same-origin' )
response . setHeader ( 'Cross-Origin-Embedder-Policy' , 'require-corp' )
// Then use SharedArrayBuffer safely
const sharedBuffer = new SharedArrayBuffer ( 1024 )
Service Worker Security
Secure your service worker implementation:
// sw.js - Handle only torrents, nothing else
self . addEventListener ( 'fetch' , ( event ) => {
const url = new URL ( event . request . url )
// Only handle /webtorrent/ paths
if ( ! url . pathname . startsWith ( '/webtorrent/' )) {
return // Let browser handle normally
}
// Validate origin
if ( url . origin !== self . location . origin ) {
event . respondWith ( new Response ( 'Forbidden' , { status: 403 }))
return
}
// Handle torrent request
event . respondWith ( handleTorrentRequest ( event . request ))
})
Iframe Sandboxing
If embedding WebTorrent in an iframe, use proper sandboxing:
< iframe
src = "/torrent-viewer.html"
sandbox = "allow-scripts allow-same-origin"
allow = "accelerometer; autoplay; encrypted-media; gyroscope;" ></ iframe >
Error Handling and Logging
Secure Error Messages
Never expose sensitive information in error messages:
client . on ( 'error' , ( err ) => {
// Log full error internally
console . error ( '[Internal]' , err )
// Show generic message to user
displayError ( 'An error occurred while downloading the torrent' )
})
torrent . on ( 'error' , ( err ) => {
// Don't expose file paths
const safeMessage = err . message
. replace ( / \/ . *? \/ / , '...' )
. replace ( /C: \\ . *? \\ / , '...' )
console . error ( 'Torrent error:' , safeMessage )
})
Audit Logging
Log security-relevant events:
class SecurityLogger {
constructor ( client ) {
this . client = client
this . setupListeners ()
}
setupListeners () {
this . client . on ( 'torrent' , ( torrent ) => {
this . log ( 'TORRENT_ADD' , {
infoHash: torrent . infoHash ,
name: torrent . name ,
size: torrent . length
})
torrent . on ( 'wire' , ( wire , addr ) => {
this . log ( 'PEER_CONNECT' , {
infoHash: torrent . infoHash ,
address: this . sanitizeAddress ( addr )
})
})
})
}
sanitizeAddress ( addr ) {
// Remove detailed port information
return addr . split ( ':' )[ 0 ] + ':***'
}
log ( event , data ) {
console . log ( JSON . stringify ({
timestamp: new Date (). toISOString (),
event ,
data
}))
}
}
const logger = new SecurityLogger ( client )
Threat Mitigation
Common Threats and Defenses
Path Traversal Threat: Malicious torrent with ../../../etc/passwd in filenameDefense: Validate all file paths, use addUID: true, restrict download directory
Resource Exhaustion Threat: Extremely large torrents consuming all disk space or memoryDefense: Set size limits, monitor resource usage, implement quotas
IP Address Exposure Threat: Browser WebRTC leaking real IP addressDefense: Use TURN relay, configure iceTransportPolicy, disable WebRTC if needed
Malicious Peers Threat: Peers sending corrupted data or attempting exploitsDefense: Automatic piece verification, IP blocklists, connection limits
Rate Limiting
Implement rate limiting to prevent abuse:
class RateLimiter {
constructor ( maxTorrentsPerHour = 10 ) {
this . maxTorrents = maxTorrentsPerHour
this . torrents = []
}
canAddTorrent () {
const oneHourAgo = Date . now () - 3600000
this . torrents = this . torrents . filter ( t => t > oneHourAgo )
if ( this . torrents . length >= this . maxTorrents ) {
return false
}
this . torrents . push ( Date . now ())
return true
}
}
const limiter = new RateLimiter ( 10 )
function addTorrent ( torrentId ) {
if ( ! limiter . canAddTorrent ()) {
throw new Error ( 'Rate limit exceeded. Try again later.' )
}
return client . add ( torrentId )
}
Security Checklist
Essential Security Measures
Responsible Development
Legal Considerations: Ensure your application complies with:
Copyright laws in your jurisdiction
DMCA and takedown requirements
Privacy regulations (GDPR, CCPA, etc.)
Terms of service for trackers and hosting
WebTorrent is a tool. How you use it is your responsibility.
Next Steps
Performance Optimize while maintaining security
BEP Support Understand protocol features and security implications