T09 · Insecure Skill Coding Practices
- Location
index.js:95- Finding
Unrestricted Local File Upload Through Untrusted TTS Output Path
- Content
View full analysis
Vulnerability Details
File Location:
index.js, lines 95-111
Vulnerability Type: Arbitrary local file disclosure caused by insufficient path validation
Risk Level: HighVulnerable Code
js const mediaPath = await duby.duby_tts({ text: options.text, voice_id: options.voice }); if (!mediaPath || !mediaPath.startsWith('MEDIA:')) { throw new Error(`Invalid TTS response: ${mediaPath}`); } const filePath = mediaPath.replace('MEDIA:', '').trim(); const absolutePath = path.resolve(process.cwd(), filePath); if (!fs.existsSync(absolutePath)) { throw new Error(`Generated audio file not found at: ${absolutePath}`); } console.log(`📤 Uploading audio: ${filePath}...`); // Step 2: Upload to Feishu const token = await getToken(); const fileKey = await uploadAudio(token, absolutePath);The selected file is subsequently read and transmitted by
uploadAudio():js const fileBuffer = fs.readFileSync(filePath); const blob = new Blob([fileBuffer]); const formData = new FormData(); formData.append('file_type', 'stream'); formData.append('file_name', fileName); formData.append('file', blob, fileName); formData.append('duration', '10000'); const response = await fetchWithRetry('https://open.feishu.cn/open-apis/im/v1/files', { method: 'POST', headers: { 'Authorization': `Bearer ${token}` }, body: formData });Technical Analysis
The Skill trusts the
MEDIA:path returned by the external sibling module../duby/index.js. It only verifies that the returned string begins withMEDIA:and that the resolved path exists. It does not ensure that the file:- Is inside a dedicated TTS output directory.
- Was created by the current TTS operation.
- Is a regular, non-symbolic-link audio file.
- Has an approved extension or media type.
- Is within an acceptable size limit.
path.resolve()accepts absolute paths and traversal sequences. Consequently, a compromised, replaced, or otherwise manipulated Duby ...[truncated 1820 chars]- Remediation
View remediation
Remediation Suggestions
- Create a dedicated private directory for generated TTS files and accept output only from that directory.
- Canonicalize both the trusted directory and returned file with
fs.realpathSync()before comparing them. - Verify that the canonical file path remains beneath the trusted directory using a path-separator-aware containment check.
- Reject symbolic links and require the result to be a regular file through
fs.lstatSync()andfs.statSync(). - Validate the file extension, detected media type, and audio format rather than trusting the filename.
- Enforce a conservative maximum file size before reading or uploading the file.
- Prefer an interface in which the TTS component returns audio bytes or a controlled file descriptor instead of an arbitrary filesystem path.
- Pin and verify the integrity of sibling components and ensure that untrusted users cannot modify them.
- Remove the generated file securely after transmission unless retention is explicitly required.
