Skip to content

VNX-212: Improper Removal of Sensitive Information Before Storage or Transfer

Detects user and account records serialised whole, password hash included: Express/Prisma handlers that res.json() a user fetched a few lines above (or res.json(await User.findById(...)) directly) with no projection or removal, Flask/Django responses built from user.__dict__ or vars(user), Django REST serializers exposing a User's password, Django serialize() of User.objects and model_to_dict(user), Laravel user models without $hidden, and Go model structs whose JSON tag exposes a password or its hash.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-212
Severity Medium
SARIF level warning
Kind sast
Languages Go, JavaScript / TypeScript, PHP, Python
CWE CWE-212
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 data-handling serialization password cwe-212
Source internal/sast/rules/vnx-212.rego

Overview

VNX-212 maps to CWE-212: Improper Removal of Sensitive Information Before Storage or Transfer. A user record usually carries a password hash, reset tokens and other fields that must never leave the server. Serialising the record as it came from the database sends them to whoever receives the response or the export; a leaked hash can be cracked offline.

Language Reported
JavaScript, TypeScript res.json(user) / res.send({ user }) where user was assigned a few lines above from a user/account/member/customer/admin lookup (findById, findOne, findByPk, find, findAll, prisma.user.findUnique/findFirst/findMany), with no .select(), attributes/exclude/omit/select: option, delete user.password or password = undefined in between
Python DRF ModelSerializer for a User/Account model with fields = "__all__" or a fields list naming password, unless the password is write_only; serializers.serialize("json", User.objects...) without fields=
PHP Laravel models extending Authenticatable (or with password in $fillable) and no $hidden naming password, $visible, #[Hidden] or makeHidden
Go struct fields holding a password hash (PasswordHash, HashedPassword, PassHash, Salt) with a JSON tag other than "-", and a Password field with a JSON tag on a persisted model (gorm/db/bson tag on the same line)

What Gets Flagged

const user = await User.findById(req.params.id);
res.json(user);                                   // FLAGGED

const saved = await user?.update({ lastLoginAt: new Date() });
res.json(saved);                                  // FLAGGED
return JsonResponse(model_to_dict(request.user))  # FLAGGED
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = "__all__"                        # FLAGGED
PasswordHash []byte `json:"password_hash,omitempty"`   // FLAGGED

What Is Not Flagged

  • User.findById(id).select('-password'), attributes: { exclude: ['password'] }, delete user.password, res.json(user.toPublicJSON()), destructuring the password away.
  • Serializers with extra_kwargs = {"password": {"write_only": True}}, or field lists without password.
  • Laravel models with protected $hidden = ['password', ...].
  • json:"-" tags, request structs (LoginRequest) that only decode a password, and a Salt in key-derivation parameters (only a user or account struct counts).
  • Models related to a user rather than the user model itself: Profile, UserProfile, UserSettings, AccountActivity.
  • Test code. A field removed by a schema option or model transform in another file is not seen; a Mongoose schema in the same file with select: false suppresses the file.

Remediation

Return a projection or a DTO, never the database record.

const user = await User.findById(id).select('name email role');
res.json(user);

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-212
// nosec vnx-212

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

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