fix: replace vulnerable ip package with ipaddr.js + node built-ins

ip had a high severity SSRF vuln (GHSA-2p57-rm9w-gvfp) with no upstream fix.
Replace with:
- net.isIPv4/isIPv6 (Node built-in) for format validation
- ipaddr.js for CIDR subnet matching

Add package-lock.json for reproducible builds (required for npm ci).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 15:45:04 +00:00
parent 09124b10b9
commit 20c6f5ead7
3 changed files with 826 additions and 5 deletions

View File

@@ -3,8 +3,9 @@ const express = require('express');
const fs = require('fs');
const path = require('path');
const rl = require('readline');
const net = require('net');
const { exec } = require('child_process');
const ipLib = require('ip');
const ipaddr = require('ipaddr.js');
const fetch = require('node-fetch');
const app = express();
@@ -220,8 +221,12 @@ async function refreshBanHistory() {
function isWhitelisted(ip) {
const wl = readIgnoreIP();
if (wl.includes(ip)) return true;
try { return SUBNETS.some(s => ipLib.cidrSubnet(s).contains(ip)); }
catch { return false; }
try {
return SUBNETS.some(s => {
const [range, bits] = ipaddr.parseCIDR(s);
return ipaddr.parse(ip).match(range, bits);
});
} catch { return false; }
}
async function processLogFile(file, cutoff) {
@@ -322,7 +327,7 @@ app.get('/api/bans', async (req, res) => {
app.post('/api/ban', async (req, res) => {
const { ip } = req.body;
if (!ip || (!ipLib.isV4Format(ip) && !ipLib.isV6Format(ip)))
if (!ip || (!net.isIPv4(ip) && !net.isIPv6(ip)))
return res.status(400).send('Invalid IP');
try { await banIP(ip); res.send(`${ip} banned.`); }
catch (e) { res.status(500).send(e.message); }