Description
Saving external network responses to local files without validation can allow arbitrary file uploads or cross a trust boundary. If the application later trusts and executes, parses, or serves those files, an attacker may inject malicious scripts or altered data into the server filesystem.
Potential impact
- Attacker-controlled files may be stored on the server and used to distribute malicious code, scripts, or altered data.
- Files saved in a public or executable directory may enable further attacks.
- Large responses may exhaust disk space or cause a denial of service.
Remediation
- Before saving a network response, validate its source, content type, size, extension, and file signature bytes.
- Use a dedicated isolated directory. Do not write directly to executable or publicly served paths.
- Where appropriate, add malware scanning, an allow-list of download destinations, and signature verification using trusted keys.
Examples
Before
javascript
const fs = require("fs");
const axios = require("axios");
async function download(url) {
const response = await axios.get(url);
fs.writeFileSync("/var/www/public/file.bin", response.data);
}
After
validateDownload and verifySignature are application-specific validation functions whose implementations are omitted. Define the validation rules and trusted signing keys, and limit download size and duration. Protect the storage directory from attacker modification.
javascript
const fs = require("fs");
const axios = require("axios");
async function download(url) {
const response = await axios.get(url, { responseType: "arraybuffer" });
const payload = validateDownload(response.data, response.headers);
await verifySignature(payload);
fs.writeFileSync("/srv/app/downloads/file.bin", payload, { mode: 0o600 });
}
Explanation:
- Before: An external response is saved to a public web path without validation, potentially serving an attacker-controlled file.
- After: Content and signatures are validated before writing to an isolated location.
mode: 0o600sets permissions when a new file is created; it does not change an existing file's permissions.