Skip to content

CWE-201: Insertion of Sensitive Information Into Sent Data - JavaScript

Overview

In JavaScript/Node.js applications, CWE-201 vulnerabilities commonly occur when developers inadvertently expose sensitive information in HTTP responses, error messages, API responses, or client-side code. The JavaScript ecosystem's flexibility and frameworks like Express, NestJS, React, and Next.js make it easy to accidentally leak passwords, tokens, API keys, environment variables, stack traces, and user PII through improper error handling, response serialization, or client-side exposure.

JavaScript applications are particularly susceptible due to several factors: Node.js's default error handling exposes stack traces, Mongoose/Sequelize models can serialize all fields including sensitive ones, environment variables can leak through webpack/bundlers to client-side code, and detailed error responses in development mode often make it to production. Additionally, logging libraries like Winston or Morgan may capture sensitive request data, and GraphQL introspection can expose internal schema details.

Common scenarios include: returning full MongoDB/Sequelize documents without field filtering, exposing .env variables in client bundles, sending error stack traces in production API responses, logging authentication tokens and passwords, including sensitive data in Redux stores accessible via browser DevTools, and accidentally committing secrets to version control. Modern frameworks provide tools like .gitignore, environment variable management, and serialization control, but developers must explicitly configure them.

Primary Defence: Use explicit field selection with .select() or Data Transfer Objects (DTOs) to control exposed fields instead of serializing entire Mongoose/Sequelize models, implement global error handlers that return generic messages while logging full details server-side, use environment variable prefixes (NEXT_PUBLIC_, REACT_APP_) to separate client/server configs, and configure Winston/Pino with custom formats to redact sensitive fields (passwords, tokens, credit cards) before logging.

This guidance demonstrates how to prevent information disclosure in JavaScript applications using proper error handling, response DTOs, secure logging, environment variable management, and client/server separation across Express, NestJS, React, and Next.js.

Common Vulnerable Patterns

Direct MongoDB/Sequelize Model Serialization

// VULNERABLE - Exposing entire database document including sensitive fields
const express = require('express');
const mongoose = require('mongoose');
const app = express();

// MongoDB schema with sensitive fields
const userSchema = new mongoose.Schema({
    username: String,
    email: String,
    passwordHash: String,    // SENSITIVE!
    resetToken: String,      // SENSITIVE!
    apiKey: String,          // SENSITIVE!
    isAdmin: Boolean,        // INTERNAL!
    creditCard: String       // SENSITIVE!
});

const User = mongoose.model('User', userSchema);

app.get('/api/user/:id', async (req, res) => {
    try {
        const user = await User.findById(req.params.id);

        // Returns ALL fields to the client!
        res.json(user);

    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

// Attack result - JSON response:
// {
//   "_id": "507f1f77bcf86cd799439011",
//   "username": "john",
//   "email": "john@example.com",
//   "passwordHash": "$2b$10$N9qo8uLOickgx2ZMRZoMye...",  ← EXPOSED!
//   "resetToken": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",  ← EXPOSED!
//   "apiKey": "sk-1234567890abcdef",                      ← EXPOSED!
//   "isAdmin": true,                                      ← INTERNAL INFO!
//   "creditCard": "4111-1111-1111-1111",                  ← EXPOSED!
//   "__v": 0
// }

Stack Traces in Production Error Responses

// VULNERABLE - Exposing internal paths, code structure, and environment details
const express = require('express');
const app = express();

app.post('/api/process', async (req, res) => {
    try {
        const result = await performDatabaseOperation(req.body);
        res.json(result);
    } catch (error) {
        // Exposes full stack trace with file paths, line numbers, dependencies
        res.status(500).json({
            error: error.message,
            type: error.name,
            stack: error.stack,  // DANGEROUS!
            code: error.code
        });
    }
});

// Attack result when error occurs:
// {
//   "error": "connect ECONNREFUSED 10.0.1.50:5432",
//   "type": "Error",
//   "stack": "Error: connect ECONNREFUSED 10.0.1.50:5432
//     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1144:16)
//     at Protocol._enqueue (/home/deploy/app/node_modules/mysql/lib/protocol/Protocol.js:144:48)
//     at Connection.query (/home/deploy/app/routes/api.js:67:18)
//     Database connection string: mysql://admin:password123@10.0.1.50:3306/production",
//   "code": "ECONNREFUSED"
// }
// ← Exposes internal IP addresses, file paths, credentials!

Environment Variables Leaked to Client

// VULNERABLE - Webpack/Vite exposing secrets to browser bundle
// .env file
/*
DATABASE_URL=postgresql://admin:secret@db.internal:5432/prod
API_KEY=sk_live_1234567890abcdef
JWT_SECRET=super-secret-jwt-key
STRIPE_SECRET_KEY=sk_test_abc123
*/

// webpack.config.js
const webpack = require('webpack');

module.exports = {
    plugins: [
        // Exposes ALL environment variables to client bundle!
        new webpack.DefinePlugin({
            'process.env': JSON.stringify(process.env)  // DANGEROUS!
        })
    ]
};

// Client-side code
const config = {
    apiUrl: process.env.API_URL,
    apiKey: process.env.API_KEY  // EXPOSED IN BROWSER!
};

// Attack: View page source or check browser DevTools
// window.process = {
//   env: {
//     DATABASE_URL: "postgresql://admin:secret@db.internal:5432/prod",  ← EXPOSED!
//     JWT_SECRET: "super-secret-jwt-key",                               ← EXPOSED!
//     STRIPE_SECRET_KEY: "sk_test_abc123",                             ← EXPOSED!
//     ...
//   }
// }

Detailed Login Error Messages

// VULNERABLE - Enables user enumeration and reveals password validation
const express = require('express');
const bcrypt = require('bcrypt');
const app = express();

app.post('/api/login', async (req, res) => {
    const { username, password } = req.body;

    const user = await User.findOne({ username });

    // Reveals whether username exists
    if (!user) {
        return res.status(404).json({
            error: `No user found with username: ${username}`  // USER ENUMERATION!
        });
    }

    // Reveals password validation details
    const passwordValid = await bcrypt.compare(password, user.passwordHash);
    if (!passwordValid) {
        return res.status(401).json({
            error: `Invalid password for user ${username}`,
            passwordHash: user.passwordHash,  // EXPOSES PASSWORD HASH!
            hint: 'Password must be at least 8 characters'
        });
    }

    res.json({ token: generateToken(user) });
});

// Attack result for enumeration:
// POST /api/login {"username": "admin"}
// Response: "No user found with username: admin"
// 
// POST /api/login {"username": "john"}
// Response: "Invalid password for user john"
// ← Attacker knows "john" exists but "admin" doesn't!

Sensitive Data in Application Logs

// VULNERABLE - Logging sensitive data accessible in log files
const express = require('express');
const winston = require('winston');
const morgan = require('morgan');

const logger = winston.createLogger({
    level: 'debug',
    format: winston.format.json(),
    transports: [new winston.transports.File({ filename: 'app.log' })]
});

const app = express();

// Logs ALL request details including sensitive data
app.use(morgan('combined'));  // LOGS EVERYTHING!

app.post('/api/payment', async (req, res) => {
    // Logs sensitive payment information
    logger.info('Processing payment', { request: req.body });  // LOGS CREDIT CARDS!

    // Logs credentials
    logger.debug(`User: ${req.body.username}, Password: ${req.body.password}`);  // DANGEROUS!

    try {
        const result = await chargeCard(req.body.cardNumber, req.body.cvv);
        res.json({ status: 'success' });
    } catch (error) {
        // Logs full request with sensitive data
        logger.error('Payment failed', { 
            request: req.body,  // LOGS SENSITIVE DATA!
            error: error.stack 
        });
        res.status(500).json({ error: 'Payment failed' });
    }
});

// app.log will contain:
// {
//   "message": "Processing payment",
//   "request": {
//     "username": "john",
//     "password": "secret123",      ← EXPOSED!
//     "cardNumber": "4111111111111111",  ← EXPOSED!
//     "cvv": "123"                  ← EXPOSED!
//   }
// }

React State Exposing Sensitive Data

// VULNERABLE - Storing sensitive data in React state visible in DevTools
import React, { useState, useEffect } from 'react';

function UserProfile() {
    const [user, setUser] = useState(null);

    useEffect(() => {
        fetch('/api/user/me')
            .then(res => res.json())
            .then(data => {
                // Stores ALL user data in React state, visible in DevTools!
                setUser(data);  // Includes passwordHash, apiKey, etc.
            });
    }, []);

    return (
        <div>
            <h1>{user?.username}</h1>
            <p>{user?.email}</p>
        </div>
    );
}

// Attack: Open React DevTools → Components tab
// UserProfile
//   useState
//     user: {
//       username: "john",
//       email: "john@example.com",
//       passwordHash: "$2b$10$...",     ← VISIBLE IN DEVTOOLS!
//       apiKey: "sk-1234567890abcdef",  ← VISIBLE IN DEVTOOLS!
//       resetToken: "abc-123-def"       ← VISIBLE IN DEVTOOLS!
//     }

Secure Patterns

DTO Pattern with Field Selection

// SECURE - Using explicit field selection and DTOs
const express = require('express');
const mongoose = require('mongoose');
const app = express();

const userSchema = new mongoose.Schema({
    username: String,
    email: String,
    passwordHash: String,
    resetToken: String,
    apiKey: String,
    isAdmin: Boolean,
    creditCard: String
});

const User = mongoose.model('User', userSchema);

// DTO class - only safe fields
class UserDTO {
    constructor(user) {
        this.id = user._id;
        this.username = user.username;
        this.email = user.email;
        // NEVER include: passwordHash, resetToken, apiKey, creditCard
    }

    static fromDocument(user) {
        return new UserDTO(user);
    }
}

app.get('/api/user/:id', async (req, res) => {
    try {
        // Select only safe fields from database
        const user = await User.findById(req.params.id)
            .select('username email')  // Explicit field selection
            .lean();  // Convert to plain object

        if (!user) {
            return res.status(404).json({ error: 'User not found' });
        }

        // Convert to DTO
        const userDTO = UserDTO.fromDocument(user);
        res.json(userDTO);

    } catch (error) {
        console.error('Error fetching user:', error);
        res.status(500).json({ 
            error: 'Failed to fetch user',
            errorCode: 'USER_FETCH_ERROR'
        });
    }
});

// Alternative: Mongoose virtuals and transform
userSchema.set('toJSON', {
    transform: function(doc, ret, options) {
        // Remove sensitive fields when converting to JSON
        delete ret.passwordHash;
        delete ret.resetToken;
        delete ret.apiKey;
        delete ret.creditCard;
        delete ret.__v;
        return ret;
    }
});

Why this works: Explicit field selection with .select() or DTOs creates an allowlist of safe fields, preventing accidental exposure when new schema fields are added. Mongoose's toJSON transform provides automatic filtering during serialization, eliminating the risk of exposing sensitive database columns like password hashes or API keys.

Global Error Handling with Generic Responses

// SECURE - Centralized error handling with generic user errors
const express = require('express');
const winston = require('winston');
const app = express();

// Configure logger for server-side only
const logger = winston.createLogger({
    level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
    format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.json()
    ),
    transports: [
        new winston.transports.File({ filename: 'error.log', level: 'error' }),
        new winston.transports.File({ filename: 'combined.log' })
    ]
});

// Custom error classes
class AppError extends Error {
    constructor(message, statusCode, errorCode) {
        super(message);
        this.statusCode = statusCode;
        this.errorCode = errorCode;
        this.isOperational = true;
    }
}

class ValidationError extends AppError {
    constructor(message) {
        super(message, 400, 'VALIDATION_ERROR');
    }
}

class NotFoundError extends AppError {
    constructor(message) {
        super(message, 404, 'NOT_FOUND');
    }
}

// Global error handler middleware
app.use((err, req, res, next) => {
    // Log full error details server-side (with stack trace)
    logger.error('Error occurred', {
        error: err.message,
        stack: err.stack,
        url: req.url,
        method: req.method,
        ip: req.ip,
        userId: req.user?.id  // If available
    });

    // Determine status code
    const statusCode = err.statusCode || 500;

    // Generic error response to client
    const errorResponse = {
        error: err.isOperational ? err.message : 'Internal server error',
        errorCode: err.errorCode || 'INTERNAL_ERROR',
        timestamp: new Date().toISOString()
    };

    // In production, never send stack traces
    if (process.env.NODE_ENV !== 'production' && !err.isOperational) {
        errorResponse.stack = err.stack;  // Only in development
    }

    res.status(statusCode).json(errorResponse);
});

// 404 handler
app.use((req, res) => {
    res.status(404).json({
        error: 'Resource not found',
        errorCode: 'NOT_FOUND'
    });
});

// Example usage in route
app.post('/api/process', async (req, res, next) => {
    try {
        const result = await performDatabaseOperation(req.body);
        res.json(result);
    } catch (error) {
        // Pass error to global handler
        next(error);
    }
});

Why this works: Centralized error handling logs full error details (including stack traces) server-side for debugging while returning only generic messages to clients. Error codes enable support tracking without exposing technical details like file paths, database information, or internal system structure. Production checks prevent stack traces from reaching users.

Secure Environment Variable Management

// SECURE - Properly managing environment variables for client/server separation

// .env (server-side only - NEVER commit to git)
/*
DATABASE_URL=postgresql://admin:secret@db.internal:5432/prod
JWT_SECRET=super-secret-jwt-key
STRIPE_SECRET_KEY=sk_live_abc123
*/

// .env.local (client-safe variables - prefix with NEXT_PUBLIC_ or REACT_APP_)
/*
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_abc123
*/

// Server-side configuration (next.config.js or separate config file)
module.exports = {
    // Server-side environment variables
    serverRuntimeConfig: {
        DATABASE_URL: process.env.DATABASE_URL,
        JWT_SECRET: process.env.JWT_SECRET,
        STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY
    },
    // Client-side environment variables (explicitly allow-listed)
    publicRuntimeConfig: {
        API_URL: process.env.NEXT_PUBLIC_API_URL,
        STRIPE_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
    },
    // Webpack config to prevent env leakage
    webpack: (config, { isServer }) => {
        if (!isServer) {
            // Don't bundle server-side modules in client bundle
            config.resolve.fallback = {
                ...config.resolve.fallback,
                fs: false,
                net: false,
                tls: false,
            };
        }
        return config;
    }
};

// Server-side API route (Next.js)
// pages/api/config.js
export default function handler(req, res) {
    // Access server-side config
    const { DATABASE_URL, JWT_SECRET } = process.env;

    // NEVER send server secrets to client
    res.json({
        apiUrl: process.env.NEXT_PUBLIC_API_URL,
        // DO NOT include DATABASE_URL, JWT_SECRET, etc.
    });
}

// Client-side component
// components/App.js
export default function App() {
    // Only public variables available on client
    const apiUrl = process.env.NEXT_PUBLIC_API_URL;

    // process.env.JWT_SECRET is undefined on client (secure!)

    return <div>API URL: {apiUrl}</div>;
}

// .gitignore (MUST include)
/*
.env
.env.local
.env.*.local
node_modules/
.next/
*/

Why this works: Prefix conventions (NEXT_PUBLIC_, REACT_APP_) create clear boundaries between server and client variables. Webpack configuration prevents server-side modules from bundling into client code. The .gitignore file prevents committing secrets to version control. Only explicitly allowlisted variables reach the browser, keeping database URLs, JWT secrets, and API keys server-side only.

Secure Login with Generic Error Messages

// SECURE - Preventing user enumeration with consistent responses
const express = require('express');
const bcrypt = require('bcrypt');
const winston = require('winston');
const app = express();

const logger = winston.createLogger({
    transports: [new winston.transports.File({ filename: 'auth.log' })]
});

const GENERIC_ERROR = 'Invalid credentials';
const DUMMY_HASH = '$2b$10$dummyhashfortimingattackprevention1234567890';

app.post('/api/login', async (req, res) => {
    const { username, password } = req.body;

    // Input validation
    if (!username || !password) {
        return res.status(401).json({ error: GENERIC_ERROR });
    }

    try {
        const user = await User.findOne({ username });

        let isValid = false;

        if (!user) {
            // Log attempt server-side
            logger.warn(`Login attempt for non-existent user: ${username}`);

            // Perform dummy hash comparison to prevent timing attacks
            await bcrypt.compare(password, DUMMY_HASH);
        } else {
            // Check actual password
            isValid = await bcrypt.compare(password, user.passwordHash);

            if (!isValid) {
                logger.warn(`Failed login attempt for user: ${username}`);
            } else {
                logger.info(`Successful login for user: ${username}`);
            }
        }

        // Return same error for both "user not found" and "wrong password"
        if (!user || !isValid) {
            return res.status(401).json({ error: GENERIC_ERROR });
        }

        // Success - return only safe data
        const token = generateToken(user);
        res.json({
            token,
            user: {
                id: user._id,
                username: user.username,
                email: user.email
                // NO passwordHash, apiKey, or other sensitive fields
            }
        });

    } catch (error) {
        logger.error('Login error', { error: error.message, username });
        res.status(500).json({ error: 'Authentication service unavailable' });
    }
});

Why this works: Identical error messages for all authentication failures prevent user enumeration attacks. The dummy hash comparison (bcrypt.compare with a fake hash) maintains constant execution time, preventing timing attacks that could reveal which usernames exist. Detailed failures are logged server-side for security monitoring, while responses contain only safe user fields.

Secure Logging with Sensitive Data Filtering

// SECURE - Custom Winston format to redact sensitive data
const winston = require('winston');
const express = require('express');

// Custom format to redact sensitive fields
const redactSensitiveData = winston.format((info) => {
    const sensitiveKeys = [
        'password', 'passwordHash', 'token', 'apiKey', 'secret',
        'creditCard', 'cardNumber', 'cvv', 'ssn', 'authorization'
    ];

    const redactObject = (obj) => {
        if (!obj || typeof obj !== 'object') return obj;

        const redacted = Array.isArray(obj) ? [...obj] : { ...obj };

        for (const key in redacted) {
            const lowerKey = key.toLowerCase();

            // Redact sensitive keys
            if (sensitiveKeys.some(sensitive => lowerKey.includes(sensitive))) {
                redacted[key] = '[REDACTED]';
            }
            // Recursively redact nested objects
            else if (typeof redacted[key] === 'object') {
                redacted[key] = redactObject(redacted[key]);
            }
            // Redact strings that look like credit cards
            else if (typeof redacted[key] === 'string') {
                redacted[key] = redacted[key].replace(
                    /\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g,
                    'XXXX-XXXX-XXXX-XXXX'
                );
            }
        }

        return redacted;
    };

    // Redact message if it's an object
    if (typeof info.message === 'object') {
        info.message = redactObject(info.message);
    }

    // Redact metadata
    for (const key in info) {
        if (key !== 'level' && key !== 'timestamp' && typeof info[key] === 'object') {
            info[key] = redactObject(info[key]);
        }
    }

    return info;
});

const logger = winston.createLogger({
    level: 'info',
    format: winston.format.combine(
        winston.format.timestamp(),
        redactSensitiveData(),
        winston.format.json()
    ),
    transports: [
        new winston.transports.File({ filename: 'error.log', level: 'error' }),
        new winston.transports.File({ filename: 'combined.log' })
    ]
});

// Custom Morgan token filter for HTTP request logging
const morgan = require('morgan');

// Don't log authorization headers
morgan.token('safe-headers', (req) => {
    const headers = { ...req.headers };
    delete headers.authorization;
    delete headers.cookie;
    return JSON.stringify(headers);
});

const app = express();

// Use custom format that excludes sensitive data
app.use(morgan(':method :url :status :response-time ms - :safe-headers', {
    stream: {
        write: (message) => logger.info(message.trim())
    }
}));

app.post('/api/payment', async (req, res) => {
    // Safe to log - sensitive fields will be redacted
    logger.info('Processing payment', { 
        userId: req.body.userId,
        amount: req.body.amount,
        cardNumber: req.body.cardNumber,  // Will be redacted
        password: req.body.password        // Will be redacted
    });

    try {
        const result = await chargeCard(req.body);
        res.json({ status: 'success', transactionId: result.id });
    } catch (error) {
        logger.error('Payment failed', { 
            userId: req.body.userId,
            error: error.message
            // Don't log sensitive request data here
        });
        res.status(500).json({ error: 'Payment processing failed' });
    }
});

Why this works: Custom Winston formats automatically redact sensitive field names (password, token, cardNumber, etc.) before writing to logs. Recursive object redaction catches nested sensitive data. Pattern matching removes credit card numbers. Morgan configuration excludes authorization headers. This provides complete audit trails while preventing credentials, payment data, and secrets from appearing in log files.

NestJS with DTOs and Class Validators

// SECURE - Using NestJS DTOs with explicit field control
import { Controller, Get, Param, UseGuards } from '@nestjs/common';
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { Exclude, Expose, plainToClass } from 'class-transformer';
import { IsString, IsEmail } from 'class-validator';

// TypeORM Entity (database model)
@Entity('users')
export class User {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    username: string;

    @Column()
    email: string;

    @Column()
    passwordHash: string;  // NEVER expose

    @Column({ nullable: true })
    resetToken: string;    // NEVER expose

    @Column({ nullable: true })
    apiKey: string;        // NEVER expose
}

// DTO for responses - only safe fields
export class UserResponseDTO {
    @Expose()
    id: number;

    @Expose()
    username: string;

    @Expose()
    email: string;

    // Explicitly exclude sensitive fields
    // (they won't be included even if present)

    static fromEntity(user: User): UserResponseDTO {
        return plainToClass(UserResponseDTO, user, {
            excludeExtraneousValues: true  // Only include @Expose() fields
        });
    }
}

@Controller('api/users')
export class UsersController {
    constructor(private readonly usersService: UsersService) {}

    @Get(':id')
    async getUser(@Param('id') id: string): Promise<UserResponseDTO> {
        const user = await this.usersService.findById(parseInt(id));

        if (!user) {
            throw new NotFoundException('User not found');
        }

        // Convert to DTO - only safe fields returned
        return UserResponseDTO.fromEntity(user);
    }
}

// Global exception filter
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';

@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
    private readonly logger = new Logger('ExceptionFilter');

    catch(exception: unknown, host: ArgumentsHost) {
        const ctx = host.switchToHttp();
        const response = ctx.getResponse<Response>();
        const request = ctx.getRequest<Request>();

        let status = 500;
        let message = 'Internal server error';
        let errorCode = 'INTERNAL_ERROR';

        if (exception instanceof HttpException) {
            status = exception.getStatus();
            message = exception.message;
        }

        // Log full error server-side
        this.logger.error(
            `${request.method} ${request.url}`,
            exception instanceof Error ? exception.stack : exception
        );

        // Return generic error to client
        response.status(status).json({
            error: message,
            errorCode,
            timestamp: new Date().toISOString(),
            path: request.url
        });
    }
}

Why this works: The class-transformer library with excludeExtraneousValues: true ensures only fields marked with @Expose() are serialized, creating an explicit allowlist. TypeORM entities remain separated from response DTOs. The global exception filter provides consistent error handling across all endpoints, logging full details server-side while sending only generic messages to clients.

Verification

After implementing the recommended secure patterns, verify the fix through multiple approaches:

  • Manual testing: Submit malicious payloads relevant to this vulnerability and confirm they're handled safely without executing unintended operations
  • Code review: Confirm all instances use the secure pattern (parameterized queries, safe APIs, proper encoding) with no string concatenation or unsafe operations
  • Static analysis: Use security scanners to verify no new vulnerabilities exist and the original finding is resolved
  • Regression testing: Ensure legitimate user inputs and application workflows continue to function correctly
  • Edge case validation: Test with special characters, boundary conditions, and unusual inputs to verify proper handling
  • Framework verification: If using a framework or library, confirm the recommended APIs are used correctly according to documentation
  • Authentication/session testing: Verify security controls remain effective and cannot be bypassed (if applicable to the vulnerability type)
  • Rescan: Run the security scanner again to confirm the finding is resolved and no new issues were introduced

Additional Resources