🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@tonnode/mcp

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tonnode/mcp - npm Package Compare versions

Comparing version
0.9.0
to
0.9.1
+26
-4
dist/http.js

@@ -38,3 +38,10 @@ // Hosted mode: the same TON MCP server over Streamable HTTP.

.filter((e) => typeof e?.key === "string" && e.key.length > 0)
.map((e) => [e.key, { rpm: e.rpm, expires: e.expires, label: e.label }]));
// `ips` was missing from this projection, so the allowlist below
// could never fire for a key loaded from the file — which is every
// key in production. The billing service validates the addresses,
// writes them into the registry and the console shows the key as
// restricted; the server then dropped the field on load and served
// the key from anywhere. Every field the auth path reads has to
// survive this map.
.map((e) => [e.key, { rpm: e.rpm, expires: e.expires, label: e.label, ips: e.ips }]));
}

@@ -88,6 +95,21 @@ catch (err) {

function clientIp(req) {
// The LAST entry, not the first.
//
// This address decides whether a key with an allowlist is accepted, so the
// question is which part of the header an attacker controls. Caddy as
// configured today REPLACES X-Forwarded-For with the real peer, so there is
// exactly one entry and either end works — verified by proxying a spoofed
// header through it.
//
// But that safety comes from the proxy, not from here. Put any appending
// proxy in front and the header becomes "<whatever the client typed>, <real
// client>": the first entry is then attacker-controlled and the allowlist
// is bypassed by sending one header. The last entry is always the one our
// own nearest proxy wrote. If that ever stops matching a customer's rule the
// failure is a refused request, not a granted one.
const fwd = req.headers["x-forwarded-for"];
const raw = Array.isArray(fwd) ? fwd[0] : fwd;
const first = (raw ?? "").split(",")[0].trim();
const addr = first || req.socket.remoteAddress || "";
const raw = Array.isArray(fwd) ? fwd[fwd.length - 1] : fwd;
const parts = (raw ?? "").split(",").map((p) => p.trim()).filter(Boolean);
const nearest = parts.length > 0 ? parts[parts.length - 1] : "";
const addr = nearest || req.socket.remoteAddress || "";
// ::ffff:1.2.3.4 → 1.2.3.4

@@ -94,0 +116,0 @@ return addr.startsWith("::ffff:") ? addr.slice(7) : addr;

+4
-3
{
"name": "@tonnode/mcp",
"mcpName": "io.github.tonnode/mcp",
"version": "0.9.0",
"description": "Liteserver access to TON: balances, account state, transactions, get-methods over native ADNL — plus non-custodial DEX swaps, cross-chain swaps, and TON wallet generation.",
"version": "0.9.1",
"description": "Liteserver access to TON: balances, account state, transactions, get-methods over native ADNL \u2014 plus non-custodial DEX swaps, cross-chain swaps, and TON wallet generation.",
"type": "module",

@@ -20,3 +20,4 @@ "bin": {

"prepublishOnly": "npm run build",
"start": "node dist/index.js"
"start": "node dist/index.js",
"test": "node --test --test-force-exit \"test/*.test.mjs\""
},

@@ -23,0 +24,0 @@ "keywords": [