fix(subtitle): validate url scheme and index to prevent local file reads
This commit is contained in:
@ -15,17 +15,40 @@ router.get('/', (req, res) => {
|
|||||||
return res.status(400).json({ error: 'URL and index parameters are required' });
|
return res.status(400).json({ error: 'URL and index parameters are required' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate URL: only allow http(s) schemes. This prevents ffmpeg protocol
|
||||||
|
// handler abuse (file://, concat:, subfile:, data:, etc.) which could
|
||||||
|
// otherwise be used to read arbitrary local files from the server.
|
||||||
|
let parsedUrl;
|
||||||
|
try {
|
||||||
|
parsedUrl = new URL(url);
|
||||||
|
} catch (e) {
|
||||||
|
return res.status(400).json({ error: 'Invalid URL' });
|
||||||
|
}
|
||||||
|
if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
|
||||||
|
return res.status(400).json({ error: 'Only http(s) URLs are allowed' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate index: must be a non-negative integer. Prevents injection of
|
||||||
|
// extra ffmpeg option tokens via the -map argument.
|
||||||
|
const indexNum = Number(index);
|
||||||
|
if (!Number.isInteger(indexNum) || indexNum < 0 || String(indexNum) !== String(index).trim()) {
|
||||||
|
return res.status(400).json({ error: 'Index must be a non-negative integer' });
|
||||||
|
}
|
||||||
|
|
||||||
const ffmpegPath = req.app.locals.ffmpegPath || 'ffmpeg';
|
const ffmpegPath = req.app.locals.ffmpegPath || 'ffmpeg';
|
||||||
// console.log(`[Subtitle] Extracting track ${index} from: ${url}`);
|
// console.log(`[Subtitle] Extracting track ${indexNum} from: ${parsedUrl.href}`);
|
||||||
|
|
||||||
const args = [
|
const args = [
|
||||||
'-hide_banner',
|
'-hide_banner',
|
||||||
'-loglevel', 'warning',
|
'-loglevel', 'warning',
|
||||||
|
// Restrict ffmpeg to safe network protocols only, as defense in depth
|
||||||
|
// against protocol handler abuse or redirects into local file reads.
|
||||||
|
'-protocol_whitelist', 'http,https,tcp,tls,crypto',
|
||||||
'-user_agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
|
'-user_agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
|
||||||
'-probesize', '5000000',
|
'-probesize', '5000000',
|
||||||
'-analyzeduration', '5000000',
|
'-analyzeduration', '5000000',
|
||||||
'-i', url,
|
'-i', parsedUrl.href,
|
||||||
'-map', `0:${index}`,
|
'-map', `0:${indexNum}`,
|
||||||
'-c:s', 'webvtt',
|
'-c:s', 'webvtt',
|
||||||
'-f', 'webvtt',
|
'-f', 'webvtt',
|
||||||
'-'
|
'-'
|
||||||
|
|||||||
Reference in New Issue
Block a user