Skip to content

VNX-1230: Exposure of Sensitive Information Through Metadata

Reports a handler that stores a user-uploaded image byte for byte, so the EXIF block it carries (GPS coordinates, device make and serial, capture time, sometimes the owner's name) is published with it when the image is served. Reported, in a file that handles images (an image/ MIME check, an image extension, or avatar/photo/picture naming) and never re-encodes or strips them (no sharp, jimp, gm, Pillow Image.open/ImageOps, piexif, exif or strip-metadata call in the file; Python's str.strip() does not count, and comment lines are ignored when judging image context): Node fs.writeFile/writeFileSync of an uploaded buffer (req.file.buffer, or a variable taken from req.file/req.files or a .buffer), express-fileupload .mv() on a req.files entry, multer({ dest }) and multer.diskStorage(); Python Flask request.files[...] .save() (directly, through a variable, or in a for loop over request.files.getlist()), Django default_storage/FileSystemStorage .save() of a request.FILES entry, and a chunks() loop copying one to disk. Not reported: images decoded and re-encoded or stripped in the same file, uploads in files with no image context (documents, CSV), comments and test files. Stripping performed in another module is not visible to this line-oriented rule.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-1230
Severity Medium
SARIF level warning
Kind sast
Languages JavaScript / TypeScript, Python
CWE CWE-1230
CAPEC CAPEC-66
ATT&CK T1190
CWSS vector CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C
Tags metadata-exposure cwe-1230
Source internal/sast/rules/vnx-1230.rego

Overview

VNX-1230 maps to CWE-1230: Exposure of Sensitive Information Through Metadata. Reports a handler that stores a user-uploaded image byte for byte, so the EXIF block it carries (GPS coordinates, device make and serial, capture time, sometimes the owner’s name) is published with it when the image is served. Reported, in a file that handles images (an image/ MIME check, an image extension, or avatar/photo/picture naming) and never re-encodes or strips them (no sharp, jimp, gm, Pillow Image.open/ImageOps, piexif, exif or strip-metadata call in the file; Python’s str.strip() does not count, and comment lines are ignored when judging image context): Node fs.writeFile/writeFileSync of an uploaded buffer (req.file.buffer, or a variable taken from req.file/req.files or a .buffer), express-fileupload .mv() on a req.files entry, multer({ dest }) and multer.diskStorage(); Python Flask request.files[…] .save() (directly, through a variable, or in a for loop over request.files.getlist()), Django default_storage/FileSystemStorage .save() of a request.FILES entry, and a chunks() loop copying one to disk. Not reported: images decoded and re-encoded or stripped in the same file, uploads in files with no image context (documents, CSV), comments and test files. Stripping performed in another module is not visible to this line-oriented rule.

Why This Matters

This weakness class (Exposure of Sensitive Information Through Metadata) creates a concrete exploit surface: the rule searches for the concrete source-level patterns most commonly associated with CWE-1230 and surfaces them for review. Each finding should be evaluated in context, the rule catches the pattern, not the context.

What Gets Flagged

const buffer = req.file?.buffer
if (!kind.mime.startsWith('image')) return res.sendStatus(415)
await fs.writeFile(`public/images/avatars/${id}.${kind.ext}`, buffer)  // FLAGGED

const clean = await sharp(req.file.buffer).rotate().toBuffer()     // re-encoded:
await fs.writeFile(target, clean)                                   // not flagged

# Python / Flask
f = request.files["avatar"]
f.save(os.path.join("static/avatars", name))   # FLAGGED

Remediation

  1. Review each flagged line and determine whether the pattern represents a real instance of CWE-1230 or a false positive.
  2. Replace the flagged construct with a documented safe alternative appropriate to your language and framework.
  3. For confirmed false positives, add a # vulnetix-ignore: VNX-1230 comment on the line.
  4. Ensure equivalent test coverage exists to prevent regression.

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-1230
// nosec vnx-1230

Or record an ignore rule: vulnetix ignore add --rule vnx-1230 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-1230.rego, cli/internal/sast/docs/vnx-1230.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.