Security Advisories (4)
CVE-2026-57079 (2026-06-30)

Net::BitTorrent versions through 2.0.1 for Perl write files outside the download directory via path traversal in peer-supplied metadata. Net::BitTorrent validates file path components only on the .torrent-file ingest path. The peer and magnet metadata path (_on_metadata_received, reached from the BEP09 ut_metadata extension) passes attacker-supplied file names straight to Storage::add_file and Storage::_parse_file_tree, where Path::Tiny's child() does not collapse "..". A v2 file tree key, a v1 files[].path element, or a single-file name containing ".." segments therefore resolves outside the download directory. Because the peer also controls the piece hashes and the served bytes, content verification passes, so a malicious magnet or peer writes attacker-chosen content to an attacker-chosen path on the downloading host.

CVE-2026-57080 (2026-06-30)

Net::BitTorrent versions through 2.0.1 for Perl allow remote memory exhaustion via an uncapped peer-wire message-length prefix. The peer-wire framing in _process_messages trusts the 4-byte length prefix sent by a connected peer with no upper bound, while receive_data appends every inbound byte to the input buffer. A peer announces a length prefix of up to about 4 GiB and then streams bytes; the decoder waits until the buffer holds the full message before processing it, so the buffer grows without limit. Peer connections are unauthenticated, so any peer in the swarm exhausts the downloading process's memory. The largest legitimate message is a 16 KiB piece block, so any announced length far above that is anomalous.

CVE-2026-57082 (2026-06-30)

Net::BitTorrent versions through 2.0.1 for Perl generate the MSE Diffie-Hellman private key with a non-cryptographic PRNG. The MSE (Message Stream Encryption) handshake derives its 160-bit Diffie-Hellman private key from Perl's rand(), a non-cryptographic drand48-class generator seeded once per process, in KeyExchange.pm. The shared secret and the RC4 keys derived from it (the SHA-1 of "keyA" or "keyB", the shared secret, and the infohash) therefore depend entirely on a predictable PRNG. The same handshake sends, in cleartext, random padding drawn from the same rand() sequence in _random_pad, immediately after the public key and the private-key draw. A passive observer of the handshake recovers the PRNG state from the cleartext padding, reconstructs the private key, computes the shared secret from the peer's public key on the wire, derives the RC4 keys, and decrypts the connection, defeating the passive-observation obfuscation MSE provides.

CVE-2026-57081 (2026-06-30)

Net::BitTorrent versions through 2.0.1 for Perl allow remote memory exhaustion via deeply nested bencoded input. bdecode recurses once per nested list or dictionary level with no depth cap, and each recursive call receives the remaining buffer by value while the list and dictionary branches capture the whole remainder, so every live recursion frame keeps its own copy of the shrinking buffer (O(N^2) bytes for an N-deep input). The decoder runs on every untrusted bencode source: .torrent files, BEP09 metadata fetched from peers, DHT messages, and tracker responses. A bencoded input of roughly 150,000 nested lists (about 150 KB on the wire) drives multi-gigabyte peak memory, so one short message from any peer, or one crafted .torrent file or magnet link, terminates the client.

NAME

Net::BitTorrent::Protocol - Packet utilities for the BitTorrent protocol

Synopsis

use Net::BitTorrent::Protocol qw[:build parse_packet];

# Tell them what we want...
my $handshake = build_handshake(
    pack('C*', split('', '00000000')),
    pack('H*', 'ddaa46b1ddbfd3564fca526d1b68420b6cd54201'),
    'your-peer-id-in-here'
);

# And the inverse...
my ($reserved, $infohash, $peerid) = parse_packet( $handshake );

Description

What would BitTorrent be without packets? TCP noise, mostly.

For similar work and links to the specifications behind these packets, move on down to the See Also section.

Exporting from Net::BitTorrent::Protocol

There are three tags available for import. To get them all in one go, use the :all tag.

:types

Packet types

For more on what these packets actually mean, see the BitTorrent Spec. This is a list of the currently supported packet types:

HANDSHAKE
KEEPALIVE
CHOKE
UNCHOKE
INTERESTED
NOT_INTERESTED
HAVE
BITFIELD
REQUEST
PIECE
CANCEL
PORT
SUGGEST
HAVE_ALL
HAVE_NONE
REJECT
ALLOWED_FAST
EXTPROTOCOL
:build

These create packets ready-to-send to remote peers. See Building Functions.

:parse

These are used to parse unknown data into sensible packets.

Building Functions

build_handshake ( RESERVED, INFOHASH, PEERID )

Creates an initial handshake packet. All parameters must conform to the BitTorrent spec:

RESERVED

...is the 8 byte string used to represent a client's capabilities for extensions to the protocol.

INFOHASH

...is the 20 byte SHA1 hash of the bencoded info from the metainfo file.

PEERID

...is 20 bytes.

build_keepalive ( )

Creates a keep-alive packet. The keep-alive packet is zero bytes, specified with the length prefix set to zero. There is no message ID and no payload. Peers may close a connection if they receive no packets (keep-alive or any other packet) for a certain period of time, so a keep- alive packet must be sent to maintain the connection alive if no command have been sent for a given amount of time. This amount of time is generally two minutes.

build_choke ( )

Creates a choke packet. The choke packet is fixed-length and has no payload.

See Also: http://tinyurl.com/NB-docs-choking - Choking and Optimistic Unchoking

build_unchoke ( )

Creates an unchoke packet. The unchoke packet is fixed-length and has no payload.

See Also: http://tinyurl.com/NB-docs-choking - Choking and Optimistic Unchoking

build_interested ( )

Creates an interested packet. The interested packet is fixed-length and has no payload.

build_not_interested ( )

Creates a not interested packet. The not interested packet is fixed-length and has no payload.

build_have ( INDEX )

Creates a have packet. The have packet is fixed length. The payload is the zero-based INDEX of a piece that has just been successfully downloaded and verified via the hash.

That is the strict definition, in reality some games may be played. In particular because peers are extremely unlikely to download pieces that they already have, a peer may choose not to advertise having a piece to a peer that already has that piece. At a minimum "HAVE suppression" will result in a 50% reduction in the number of HAVE packets, this translates to around a 25-35% reduction in protocol overhead. At the same time, it may be worthwhile to send a HAVE packet to a peer that has that piece already since it will be useful in determining which piece is rare.

A malicious peer might also choose to advertise having pieces that it knows the peer will never download. Due to this attempting to model peers using this information is a bad idea.

build_bitfield ( BITFIELD )

Creates a bitfield packet. The bitfield packet is variable length, where X is the length of the BITFIELD. The payload is a BITFIELD representing the pieces that have been successfully downloaded. The high bit in the first byte corresponds to piece index 0. Bits that are cleared indicated a missing piece, and set bits indicate a valid and available piece. Spare bits at the end are set to zero.

A bitfield packet may only be sent immediately after the handshaking sequence is completed, and before any other packets are sent. It is optional, and need not be sent if a client has no pieces or uses one of the Fast Extension packets: have all or have none.

build_request ( INDEX, OFFSET, LENGTH )

Creates a request packet. The request packet is fixed length, and is used to request a block. The payload contains the following information:

INDEX

...is an integer specifying the zero-based piece index.

OFFSET

...is an integer specifying the zero-based byte offset within the piece.

LENGTH

...is an integer specifying the requested length.

See Also: build_cancel

build_piece ( INDEX, OFFSET, DATA )

Creates a piece packet. The piece packet is variable length, where X is the length of the DATA. The payload contains the following information:

INDEX

...is an integer specifying the zero-based piece index.

OFFSET

...is an integer specifying the zero-based byte offset within the piece.

DATA

...is the block of data, which is a subset of the piece specified by INDEX.

Before sending pieces to remote peers, the client should verify that the piece matches the SHA1 hash related to it in the .torrent metainfo.

build_cancel ( INDEX, OFFSET, LENGTH )

Creates a cancel packet. The cancel packet is fixed length, and is used to cancel block requests. The payload is identical to that of the request packet. It is typically used during 'End Game.'

See Also: http://tinyurl.com/NB-docs-EndGame - End Game

build_extended ( DATA )

Creates an extended protocol packet.

Legacy Packets

The following packets are either part of the base protocol or one of the common extensions but have either been superseded or simply removed from the majority of clients. I have provided them here only for legacy support; they will not be removed in the future.

build_port ( PORT )

Creates a port packet.

See also: http://bittorrent.org/beps/bep_0003.html - The BitTorrent Protocol Specification

build_allowed_fast ( INDEX )

Creates an Allowed Fast packet.

uTorrent never advertises a fast set... why should we?

See also: http://bittorrent.org/beps/bep_0006.html - Fast Extension

build_suggest ( INDEX )

Creates a Suggest Piece packet.

Super seeding is not supported by Net::BitTorrent. Yet.

See also: http://bittorrent.org/beps/bep_0006.html - Fast Extension

build_reject ( INDEX, OFFSET, LENGTH )

Creates a Reject Request packet.

See also: http://bittorrent.org/beps/bep_0006.html - Fast Extension

build_have_all ( )

Creates a Have All packet.

See also: http://bittorrent.org/beps/bep_0006.html - Fast Extension

build_have_none ( )

Creates a Have None packet.

See also: http://bittorrent.org/beps/bep_0006.html - Fast Extension

Parsing Function(s)

parse_packet( DATA )

Attempts to parse any known packet from the data (a scalar ref) passed to it. On success, the payload and type are returned and the packet is removed from the incoming data ref. undef is returned on failure.

See Also

http://bittorrent.org/beps/bep_0003.html - The BitTorrent Protocol Specification

http://bittorrent.org/beps/bep_0006.html - Fast Extension

http://bittorrent.org/beps/bep_0010.html - Extension Protocol

http://wiki.theory.org/BitTorrentSpecification - An annotated guide to the BitTorrent protocol

Net::BitTorrent::PeerPacket - by Joshua McAdams

Author

Sanko Robinson <sanko@cpan.org> - http://sankorobinson.com/

CPAN ID: SANKO

License and Legal

Copyright (C) 2008-2010 by Sanko Robinson <sanko@cpan.org>

This program is free software; you can redistribute it and/or modify it under the terms of The Artistic License 2.0. See the LICENSE file included with this distribution or notes on the Artistic License 2.0 for clarification.

When separated from the distribution, all original POD documentation is covered by the Creative Commons Attribution-Share Alike 3.0 License. See the clarification of the CCA-SA3.0.

Neither this module nor the Author is affiliated with BitTorrent, Inc.