
Research
TeamPCP Compromises Telnyx Python SDK to Deliver Credential-Stealing Malware
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.
___ ____ _____ ____
|_ _| _ \ |_ _/ ___|
| || |_) |_____| | \___ \
| || __/_____| | ___) |
|___|_| |_| |____/
node-ip-ts is a full TypeScript rewrite of the popular ip package —
rebuilt from the ground up with strict types, ES Modules, and zero external dependencies.
Installation · Quick Start · API Reference · Contributing
The original ip package has millions of weekly downloads but ships no TypeScript types and only supports CommonJS. node-ip-ts solves that:
ip | node-ip-ts | |
|---|---|---|
| TypeScript support | ❌ | ✅ |
| ES Module support | ❌ | ✅ |
| CommonJS support | ✅ | ✅ |
| Type declarations | ❌ | ✅ |
| Strict null checks | ❌ | ✅ |
| External dependencies | 0 | 0 |
| API compatibility | — | ✅ drop-in |
All functions except address() work in both Node.js and browser/bundler environments (Vite, webpack, esbuild, etc.).
| Function | Node.js | Browser |
|---|---|---|
| All IP/subnet/bitwise functions | ✅ | ✅ |
loopback() | ✅ | ✅ |
address() | ✅ | ❌ (uses os module) |
If you need an IP in a browser context, obtain it server-side and pass it to the client, or use loopback() as a fallback.
# npm
npm install node-ip-ts
# pnpm
pnpm add node-ip-ts
# yarn
yarn add node-ip-ts
Requirements: Node.js ≥ 16
import * as ip from 'node-ip-ts';
// Address classification
ip.isPrivate('192.168.1.1'); // true
ip.isPublic('8.8.8.8'); // true
ip.isLoopback('127.0.0.1'); // true
// Subnet operations
ip.cidr('192.168.1.134/26'); // '192.168.1.128'
const subnet = ip.cidrSubnet('192.168.1.134/26');
subnet.contains('192.168.1.180'); // true
// Conversion
ip.toLong('255.255.255.255'); // 4294967295
ip.fromLong(4294967295); // '255.255.255.255'
import { isPrivate, cidrSubnet, toLong } from 'node-ip-ts';
const ip = require('node-ip-ts');
ip.isPrivate('10.0.0.1'); // true
isPrivate(addr: string): booleanReturns true if the address falls within any private/reserved range:
10.0.0.0/8 — RFC 1918172.16.0.0/12 — RFC 1918192.168.0.0/16 — RFC 1918169.254.0.0/16 — link-localfc00::/7 — IPv6 ULAfe80::/10 — IPv6 link-local::1, :: — loopbackip.isPrivate('192.168.0.1'); // true
ip.isPrivate('10.0.0.1'); // true
ip.isPrivate('fd12:3456:789a:1::1'); // true (IPv6 ULA)
ip.isPrivate('::ffff:192.168.0.1'); // true (IPv4-mapped IPv6)
ip.isPrivate('8.8.8.8'); // false
isPublic(addr: string): booleanInverse of isPrivate. Returns true for publicly routable addresses.
ip.isPublic('1.1.1.1'); // true
ip.isPublic('10.0.0.1'); // false
isLoopback(addr: string): booleanReturns true for loopback addresses. Supports dotted-decimal, octal, hexadecimal, and long-integer notation.
ip.isLoopback('127.0.0.1'); // true
ip.isLoopback('::1'); // true
ip.isLoopback('0x7f.0.0.1'); // true (hex notation)
ip.isLoopback('0177.0.0.1'); // true (octal notation)
ip.isLoopback('2130706433'); // true (integer notation)
ip.isLoopback('8.8.8.8'); // false
isV4Format(ip: string): booleanip.isV4Format('192.168.0.1'); // true
ip.isV4Format('::1'); // false
isV6Format(ip: string): booleanip.isV6Format('::1'); // true
ip.isV6Format('::ffff:192.168.0.1'); // true
ip.isV6Format('192.168.0.1'); // false
cidr(cidrString: string): stringReturns the network address for a given CIDR string.
ip.cidr('192.168.1.134/26'); // '192.168.1.128'
ip.cidr('2607:f0d0:1002:51::4/56'); // '2607:f0d0:1002::'
cidrSubnet(cidrString: string): SubnetInfoReturns a full SubnetInfo object for a given CIDR string.
const s = ip.cidrSubnet('192.168.1.134/26');
s.networkAddress; // '192.168.1.128'
s.firstAddress; // '192.168.1.129'
s.lastAddress; // '192.168.1.190'
s.broadcastAddress; // '192.168.1.191'
s.subnetMask; // '255.255.255.192'
s.subnetMaskLength; // 26
s.numHosts; // 62
s.length; // 64
s.contains('192.168.1.150'); // true
s.contains('192.168.1.200'); // false
subnet(addr: string, mask: string): SubnetInfoSame as cidrSubnet but takes address and mask separately.
const s = ip.subnet('192.168.1.134', '255.255.255.192');
mask(addr: string, mask: string): stringApplies a subnet mask to an address via bitwise AND.
ip.mask('192.168.1.134', '255.255.255.0'); // '192.168.1.0'
ip.mask('192.168.1.134', '::ffff:ff00'); // '::ffff:c0a8:100'
fromPrefixLen(prefixlen: number, family?: string | number): stringConverts a prefix length to a subnet mask string.
ip.fromPrefixLen(24); // '255.255.255.0'
ip.fromPrefixLen(64); // 'ffff:ffff:ffff:ffff::' (auto-detects IPv6)
ip.fromPrefixLen(24, 'ipv6'); // 'ffff:ff00::'
not(addr: string): stringBitwise NOT — useful for computing wildcard masks.
ip.not('255.255.255.0'); // '0.0.0.255'
or(a: string, b: string): stringBitwise OR. Supports same-protocol and mixed IPv4/IPv6 inputs.
ip.or('0.0.0.255', '192.168.1.10'); // '192.168.1.255'
ip.or('::ff', '::abcd:dcba:abcd:dcba'); // '::abcd:dcba:abcd:dcff'
ip.or('0.0.0.255', '::abcd:dcba:abcd:dcba'); // '::abcd:dcba:abcd:dcff'
isEqual(a: string, b: string): booleanDeep equality check, IPv4/IPv6 aware (e.g. 127.0.0.1 equals ::ffff:7f00:1).
ip.isEqual('127.0.0.1', '::ffff:127.0.0.1'); // true
ip.isEqual('127.0.0.1', '::7f00:1'); // true
ip.isEqual('127.0.0.1', '::7f00:2'); // false
toBuffer(ip: string, buff?: Buffer, offset?: number): BufferConverts an IP string to a raw Buffer (4 bytes for IPv4, 16 for IPv6). Optionally writes into an existing buffer at a given offset.
ip.toBuffer('127.0.0.1');
// <Buffer 7f 00 00 01>
const buf = Buffer.alloc(128);
ip.toBuffer('127.0.0.1', buf, 64);
// writes 4 bytes into buf at offset 64
toString(buff: Buffer, offset?: number, length?: number): stringConverts a Buffer back to an IP address string.
ip.toString(Buffer.from('7f000001', 'hex')); // '127.0.0.1'
ip.toString(buf, 64, 4); // '127.0.0.1'
toLong(ip: string): numberConverts a dotted-decimal IPv4 address to an unsigned 32-bit integer.
ip.toLong('127.0.0.1'); // 2130706433
ip.toLong('255.255.255.255'); // 4294967295
fromLong(ipl: number): stringConverts an unsigned 32-bit integer back to dotted-decimal.
ip.fromLong(2130706433); // '127.0.0.1'
ip.fromLong(4294967295); // '255.255.255.255'
normalizeToLong(addr: string): numberNormalizes an IPv4 address in any notation (decimal, octal, hex, compact) to an unsigned long. Returns -1 on invalid input.
ip.normalizeToLong('127.0.0.1'); // 2130706433 (standard)
ip.normalizeToLong('0x7f.0x0.0x0.1'); // 2130706433 (hex)
ip.normalizeToLong('0177.0.0.01'); // 2130706433 (octal)
ip.normalizeToLong('0x7f000001'); // 2130706433 (single hex)
ip.normalizeToLong('127.1'); // 2130706433 (compact)
ip.normalizeToLong('256.0.0.1'); // -1 (invalid)
address(name?: string, family?: string | number): string⚠️ Node.js only. This function uses the
osmodule which is not available in browsers.
Calling it in a browser environment will throw a descriptive error. All other functions work in both environments.
Returns an IP address from the current machine's network interfaces.
ip.address(); // first private IPv4 address, e.g. '192.168.1.42'
ip.address('public'); // first public IPv4 address
ip.address('private'); // first private IPv4 address
ip.address('eth0'); // first IPv4 address on eth0
ip.address('eth0', 6); // first IPv6 address on eth0
Falls back to loopback() if no matching interface is found.
loopback(family?: string | number): stringReturns the loopback address for the given IP family.
ip.loopback(); // '127.0.0.1'
ip.loopback('ipv4'); // '127.0.0.1'
ip.loopback('ipv6'); // 'fe80::1'
import type { IPFamily, SubnetInfo } from 'node-ip-ts';
type IPFamily = 'ipv4' | 'ipv6';
interface SubnetInfo {
networkAddress: string;
firstAddress: string;
lastAddress: string;
broadcastAddress: string;
subnetMask: string;
subnetMaskLength: number;
numHosts: number;
length: number;
contains(other: string): boolean;
}
node-ip-ts/
├── src/
│ └── index.ts # Single source file — all named exports
├── dist/
│ ├── esm/ # ES Module build (.js + .js.map)
│ ├── cjs/ # CommonJS build (.js + .js.map)
│ └── types/ # Type declarations (.d.ts + .d.ts.map)
├── __tests__/
│ └── ip.test.ts # Jest test suite
├── tsconfig.esm.json
├── tsconfig.cjs.json
├── tsconfig.types.json
└── package.json
Contributions are welcome! Here's how to get started:
# Clone the repo
git clone https://github.com/denycode-dev/ip-ts.git
cd node-ip-ts
# Install dependencies
npm install
# Run tests
npm test
# Build
npm run build
npm test)Please open an issue with a minimal reproduction case.
ipnode-ip-ts is designed to be a drop-in replacement. Simply swap your import:
- const ip = require('ip');
+ const ip = require('node-ip-ts');
Or for TypeScript / ESM:
import * as ip from 'node-ip-ts';
All function names and behaviours are identical to the original library.
MIT © Deni Irawan Nugraha
FAQs
Modern TypeScript IP address utility library — ESM, CJS, and browser ready
We found that node-ip-ts demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.

Security News
/Research
Widespread GitHub phishing campaign uses fake Visual Studio Code security alerts in Discussions to trick developers into visiting malicious website.