Files
worldmonitor/api/yahoo-finance.js
Elie Habib ce7d22a4a6 Validate proxy endpoint parameters
polymarket.js:
- Allowlist order values (volume, liquidity, startDate, endDate, spread)
- Clamp limit to 1-100 range
- Validate boolean params (closed, ascending)

coingecko.js:
- Limit coin IDs to max 20, validate format (alphanumeric + hyphens)
- Allowlist currencies (usd, eur, gbp, jpy, cny, btc, eth)
- Validate boolean include_24hr_change

yahoo-finance.js:
- Validate symbol format (alphanumeric, dots, hyphens, max 20 chars)
- Return 400 for invalid symbols

Prevents abuse via unbounded params that could trigger upstream rate
limits or inflate egress costs.
2026-01-11 11:14:01 +04:00

49 lines
1.5 KiB
JavaScript

export const config = { runtime: 'edge' };
const SYMBOL_PATTERN = /^[A-Za-z0-9.^=\-]+$/;
const MAX_SYMBOL_LENGTH = 20;
function validateSymbol(symbol) {
if (!symbol) return null;
const trimmed = symbol.trim().toUpperCase();
if (trimmed.length > MAX_SYMBOL_LENGTH) return null;
if (!SYMBOL_PATTERN.test(trimmed)) return null;
return trimmed;
}
export default async function handler(req) {
const url = new URL(req.url);
const symbol = validateSymbol(url.searchParams.get('symbol'));
if (!symbol) {
return new Response(JSON.stringify({ error: 'Invalid or missing symbol parameter' }), {
status: 400,
headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' },
});
}
try {
const yahooUrl = `https://query1.finance.yahoo.com/v8/finance/chart/${encodeURIComponent(symbol)}`;
const response = await fetch(yahooUrl, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
},
});
const data = await response.text();
return new Response(data, {
status: response.status,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'public, max-age=60',
},
});
} catch (error) {
return new Response(JSON.stringify({ error: 'Failed to fetch data' }), {
status: 500,
headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' },
});
}
}