BACK TO SEARCH
mcpflow/alexanimal_tradovate-mcp-servercritical

Mirror of https://github.com/alexanimal/tradovate-mcp-server

This MCP server provides an interface to the Tradovate futures trading API, allowing users to manage contracts, positions, orders, and accounts. It ex...

purpose: This MCP server provides an interface to the Tradothreat: local with credentials
0 · May 21, 2026 · May 21, 2026 · GITHUB ↗
RISK SCORE
0/ 100 risk
medium findings+150
capped at100
VULNERABILITY ANALYSIS · 10 findings in 10 blocks0 HIGH · 10 MEDIUM
MEDIUM1 finding
src/index.ts:258
258server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
259  const uri = request.params.uri;
260  
261  // Parse the URI to get the resource type and ID
262  // Handle both tradovate:// protocol scheme and simple tradovate/ format
263  const match = uri.match(/^(?:tradovate:\/\/|tradovate\/)([^\/]+)(?:\/(.*))?$/);
264  
265  if (!match) {
266    throw new Error(`Invalid resource URI: ${uri}`);
267  }
268  
269  const resourceType = match[1];
270  const resourceId = match[2] || '';
271  
272  if (!resourceType) {
273    throw new Error(`Invalid resource URI: ${uri}`);
274  }
275  
276  // Handle different resource types
277  switch (resourceType) {
278    case "contract": {
279      if (resourceId) {
280        // Return specific contract
281        const contract = contractsCache[resourceId];
282        if (!contract) {
283          throw new Error(`Resource not found: ${uri}`);
284        }
285        
286        return {
287          contents: [
288            {
289              type: "application/json",
290              text: JSON.stringify(contract),
291              uri: `tradovate://contract/${resourceId}`
292            },
293          ],
294        };
295      } else {
296        // Return list of contracts
297        const contracts = Object.values(contractsCache);
298        
299        return {
300          contents: [
301            {
302              type: "application/json",
303              text: JSON.stringify(contracts),
304              uri: "tradovate://contract/"
305            },
306          ],
307        };
308      }
309    }
310    
311    case "position": {
312      if (resourceId) {
313        // Return specific position - fetch directly from API
314        try {
315          const position = await tradovateRequest('GET', `position/find?id=${resourceId}`);
src/index.ts:258

// Local-only MCP, requires compromised LLM to exploit

EXPLAINThe resourceId extracted from the URI is directly interpolated into the API endpoint URL without validation. An attacker could inject additional query parameters or path segments via the URI.
IMPACTA compromised LLM could craft a URI like 'tradovate://position/1&admin=true' to manipulate the API request, potentially accessing unintended endpoints or performing parameter pollution.
FIXValidate resourceId as a numeric value or against a whitelist of allowed characters.
MEDIUM1 finding
src/tools.ts:632
632export async function handleGetMarketData(request: any) {
633  const symbol = String(request.params.arguments?.symbol);
634  const dataType = String(request.params.arguments?.dataType);
635  const chartTimeframe = String(request.params.arguments?.chartTimeframe || "1min");
636
637  if (!symbol || !dataType) {
638    throw new Error("Symbol and dataType are required");
639  }
640
641  try {
642    // Find contract by symbol
643    const contract = await tradovateRequest('GET', `contract/find?name=${symbol}`);
src/index.ts:564src/tools.ts:632

// Local-only MCP, requires compromised LLM to exploit

EXPLAINThe symbol parameter is directly interpolated into the API endpoint URL without validation. An attacker could inject additional query parameters or path segments.
IMPACTA compromised LLM could craft a symbol value to manipulate the API request, potentially accessing unintended endpoints or performing parameter pollution.
FIXValidate the symbol parameter against a whitelist of allowed characters.
MEDIUM1 finding
src/tools.ts:501
501export async function handleGetAccountSummary(request: any) {
502  const accountId = String(request.params.arguments?.accountId || "");
503  
504  try {
505    // Get accounts
506    let accounts;
507    if (accountId) {
508      accounts = [await tradovateRequest('GET', `account/find?id=${accountId}`)];
src/index.ts:561src/tools.ts:501

// Local-only MCP, requires compromised LLM to exploit

EXPLAINThe accountId parameter is directly interpolated into the API endpoint URL without validation. An attacker could inject additional query parameters or path segments.
IMPACTA compromised LLM could manipulate accountId to access other accounts' data or perform parameter injection.
FIXValidate accountId as a numeric value or against a whitelist of allowed account IDs.
MEDIUM1 finding
src/tools.ts:810
810export async function handleListOrders(request: any) {
811  const accountId = String(request.params.arguments?.accountId || "");
812  
813  try {
814    // Get orders from API
815    let endpoint = 'order/list';
816    if (accountId) {
817      endpoint += `?accountId=${accountId}`;
818    }
src/index.ts:567src/tools.ts:810

// Local-only MCP, requires compromised LLM to exploit

EXPLAINThe accountId parameter is directly concatenated into the API endpoint URL without validation. An attacker could inject additional query parameters or modify the endpoint path.
IMPACTA compromised LLM could manipulate accountId to access other accounts' orders or perform parameter injection.
FIXValidate accountId as a numeric value or against a whitelist of allowed account IDs.
MEDIUM1 finding
src/tools.ts:8
8export async function handleGetContractDetails(request: any) {
9  const symbol = String(request.params.arguments?.symbol);
10  if (!symbol) {
11    throw new Error("Symbol is required");
12  }
13
14  try {
15    // Find contract by symbol
16    const contract = await tradovateRequest('GET', `contract/find?name=${symbol}`);
src/index.ts:543src/tools.ts:8

// Local-only MCP, requires compromised LLM to exploit

EXPLAINThe symbol parameter is directly interpolated into the API endpoint URL without any validation or sanitization. An attacker could inject additional query parameters or path segments, potentially accessing unintended API endpoints or performing parameter pollution.
IMPACTA compromised LLM could craft a symbol value like 'ESZ4&admin=true' or '../admin/delete' to manipulate API requests beyond the intended scope.
FIXValidate the symbol parameter against a whitelist of allowed characters (e.g., alphanumeric and specific symbols) and reject any input containing special characters like '&', '/', '?', etc.
MEDIUM1 finding
src/tools.ts:60
60export async function handleListPositions(request: any) {
61  const accountId = String(request.params.arguments?.accountId || "");
62  
63  try {
64    // Get positions from API
65    let endpoint = 'position/list';
66    if (accountId) {
67      endpoint += `?accountId=${accountId}`;
68    }
src/index.ts:546src/tools.ts:60

// Local-only MCP, requires compromised LLM to exploit

EXPLAINThe accountId parameter is directly concatenated into the API endpoint URL without validation. An attacker could inject additional query parameters or modify the endpoint path.
IMPACTA compromised LLM could manipulate accountId to access other accounts' data or perform parameter injection attacks.
FIXValidate accountId as a numeric value or against a whitelist of allowed account IDs.
MEDIUM1 finding
src/tools.ts:263
263export async function handleModifyOrder(request: any) {
264  const orderId = String(request.params.arguments?.orderId);
265  const price = request.params.arguments?.price !== undefined ? Number(request.params.arguments.price) : undefined;
266  const stopPrice = request.params.arguments?.stopPrice !== undefined ? Number(request.params.arguments.stopPrice) : undefined;
267  const quantity = request.params.arguments?.quantity !== undefined ? Number(request.params.arguments.quantity) : undefined;
268
269  if (!orderId) {
270    throw new Error("Order ID is required");
271  }
272
273  try {
274    // Find order by ID
275    const order = await tradovateRequest('GET', `order/find?id=${orderId}`);
src/index.ts:552src/tools.ts:263

// Local-only MCP, requires compromised LLM to exploit

EXPLAINThe orderId parameter is directly interpolated into the API endpoint URL without validation. An attacker could inject additional query parameters or path segments.
IMPACTA compromised LLM could manipulate orderId to access or modify orders belonging to other users or perform parameter injection.
FIXValidate orderId as a numeric value and reject non-numeric input.
MEDIUM1 finding
src/tools.ts:131
131export async function handlePlaceOrder(request: any) {
132  const symbol = String(request.params.arguments?.symbol);
133  const action = String(request.params.arguments?.action);
134  const orderType = String(request.params.arguments?.orderType);
135  const quantity = Number(request.params.arguments?.quantity);
136  const price = request.params.arguments?.price ? Number(request.params.arguments.price) : undefined;
137  const stopPrice = request.params.arguments?.stopPrice ? Number(request.params.arguments.stopPrice) : undefined;
138
139  if (!symbol || !action || !orderType || !quantity) {
140    throw new Error("Symbol, action, orderType, and quantity are required");
141  }
142
143  // Validate order type and required parameters - moved up before any API calls
144  if ((orderType === "Limit" || orderType === "StopLimit") && price === undefined) {
145    throw new Error("Price is required for Limit and StopLimit orders");
146  }
147
148  if ((orderType === "Stop" || orderType === "StopLimit") && stopPrice === undefined) {
149    throw new Error("Stop price is required for Stop and StopLimit orders");
150  }
151
152  try {
153    // Find contract by symbol
154    const contract = await tradovateRequest('GET', `contract/find?name=${symbol}`);
src/index.ts:549src/tools.ts:131

// Local-only MCP, requires compromised LLM to exploit

EXPLAINThe symbol parameter is directly interpolated into the API endpoint URL without validation. An attacker could inject additional query parameters or path segments.
IMPACTA compromised LLM could craft a symbol value to manipulate the API request, potentially accessing unintended endpoints or performing parameter pollution.
FIXValidate the symbol parameter against a whitelist of allowed characters (e.g., alphanumeric and specific symbols) and reject any input containing special characters.
MEDIUM1 finding
src/tools.ts:398
398export async function handleLiquidatePosition(request: any) {
399  const symbol = String(request.params.arguments?.symbol);
400
401  if (!symbol) {
402    throw new Error("Symbol is required");
403  }
404
405  try {
406    // Find contract by symbol
407    const contract = await tradovateRequest('GET', `contract/find?name=${symbol}`);
src/index.ts:558src/tools.ts:398

// Local-only MCP, requires compromised LLM to exploit

EXPLAINThe symbol parameter is directly interpolated into the API endpoint URL without validation. An attacker could inject additional query parameters or path segments.
IMPACTA compromised LLM could craft a symbol value to manipulate the API request, potentially accessing unintended endpoints or performing parameter pollution.
FIXValidate the symbol parameter against a whitelist of allowed characters.
MEDIUM1 finding
src/auth.ts:60
60  // Debug log for credentials
61  logger.debug('DEBUG: Credentials retrieved from environment:');
62  logger.debug('name present:', !!credentials.name);
63  logger.debug('password present:', !!credentials.password);
64  logger.debug('appId present:', !!credentials.appId);
65  logger.debug('deviceId present:', !!credentials.deviceId);
66  logger.debug('cid present:', !!credentials.cid);
67  logger.debug('sec present:', !!credentials.sec);
src/index.ts:16src/auth.ts:3

// Local-only MCP, requires compromised LLM to exploit

EXPLAINThe getCredentials() function logs whether each credential is present using logger.debug. While it does not log the actual values, it reveals which credentials are set, aiding an attacker in understanding the authentication setup. Under local_with_credentials threat model, a compromised LLM could enable debug logging and infer credential presence.
IMPACTAn attacker with access to logs could determine which credentials are configured, potentially guiding further attacks.
FIXRemove debug logging of credential presence or ensure it is only enabled in development and never in production.
5/21/2026
Findings are produced by automated LLM analysis and may include false positives or miss issues. Verify independently before acting.