Skip to content

Commit 24345dc

Browse files
fix code scanning alert: Server-side request forgery
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
1 parent 6ba74de commit 24345dc

1 file changed

Lines changed: 19 additions & 6 deletions

File tree

routes/auth.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import rateLimit from 'express-rate-limit';
33
import argon2 from 'argon2';
44
import jwt from 'jsonwebtoken';
55
import { createHash, randomBytes } from 'crypto';
6+
import { isIP } from 'net';
67

78
import { query } from '../config/db.js';
89
import { generateToken, authenticateToken } from '../middleware/auth.js';
@@ -99,16 +100,28 @@ function isPrivateIp(ip) {
99100
return false;
100101
}
101102

102-
async function isVpnOrProxy(ip) {
103-
if (isPrivateIp(ip)) {
104-
console.log('[VPN] Skipping private IP:', ip);
103+
function normalizeClientIp(ip) {
104+
if (typeof ip !== 'string') return null;
105+
const trimmed = ip.trim();
106+
if (!trimmed) return null;
107+
const withoutV4Mapped = trimmed.replace(/^::ffff:/, '');
108+
return isIP(withoutV4Mapped) ? withoutV4Mapped : null;
109+
}
110+
111+
export async function isVpnOrProxy(ip) {
112+
const cleanIp = normalizeClientIp(ip);
113+
if (!cleanIp) {
114+
console.log('[VPN] Skipping invalid IP:', ip);
105115
return false;
106116
}
107117

108-
const cleanIp = ip.replace(/^::ffff:/, '');
118+
if (isPrivateIp(cleanIp)) {
119+
console.log('[VPN] Skipping private IP:', cleanIp);
120+
return false;
121+
}
109122

110123
try {
111-
const res = await fetchWithTimeout(`http://ip-api.com/json/${cleanIp}?fields=proxy,hosting,isp,org,query`);
124+
const res = await fetchWithTimeout(`http://ip-api.com/json/${encodeURIComponent(cleanIp)}?fields=proxy,hosting,isp,org,query`);
112125
const data = await res.json();
113126
console.log('[VPN] ip-api response for', cleanIp, ':', JSON.stringify(data));
114127
return data.proxy === true || data.hosting === true;
@@ -117,7 +130,7 @@ async function isVpnOrProxy(ip) {
117130
}
118131

119132
try {
120-
const res = await fetchWithTimeout(`https://ipinfo.io/${cleanIp}/json`);
133+
const res = await fetchWithTimeout(`https://ipinfo.io/${encodeURIComponent(cleanIp)}/json`);
121134
const data = await res.json();
122135
console.log('[VPN] ipinfo response for', cleanIp, ':', JSON.stringify({ org: data.org }));
123136
const orgLower = (data.org || '').toLowerCase();

0 commit comments

Comments
 (0)