Skip to main content

Security Scanner

The Security Scanner is an advanced input sanitization and threat detection module for protecting your forms from malicious input. It detects multiple attack vectors including SQL Injection, XSS, NoSQL Injection, Path Traversal, and sensitive token leakage.

Overview

The Scanner class provides comprehensive protection by:

  1. Normalizing obfuscated input - Removes encoding layers that hide malicious code
  2. Detecting obfuscation attempts - Flags suspicious invisible characters
  3. Pattern-based threat detection - Identifies 5 major threat categories
  4. Customizable rules - Extend with organization-specific patterns
  5. Performance tuning - Early termination and targeted scanning options

Key Features

Multi-Layer Normalization — Defeats URL encoding, HTML entities, JavaScript escapes, zero-width characters
5 Threat Categories — SQL Injection, NoSQL Injection, XSS, Path Traversal, Token Leakage
Configurable Strictness — Adjust threat classification to match your security requirements
HTML Context Awareness — Allows safe tags while blocking dangerous ones
Detailed Recommendations — Actionable remediation advice for each threat
Performance Optimized — Optional early termination and async scanning
Zero Dependencies — Pure TypeScript/JavaScript, no external libraries

const { Scanner } = require('@gd3v/veli');

Quick Start

// Create a scanner with default settings (safe & balanced)
const scanner = new Scanner();

// Scan fields for all threat types
const result = scanner.scanAll([
{ name: 'username', value: 'john_doe', type: 'text' },
{ name: 'bio', value: '<p>Hello world</p>', type: 'html', allowedTags: ['p', 'br'] },
{ name: 'comment', value: "'; DROP TABLE users; --", type: 'text' }
]);

if (result.passed) {
console.log('All fields are secure!');
} else {
console.log('Security threats detected:', result.result);
}

Configuration

Creating a Scanner with Options

const scanner = new Scanner({
strictMode: false, // default: false
stopOnFirstThreat: false, // default: false
includeValueInResponse: false, // default: false
customPatterns: {} // default: {}
});

Configuration Parameters

strictMode (boolean, default: false)

Controls threat classification strictness.

  • When false: MEDIUM severity threats are reported as-is
  • When true: MEDIUM severity threats are elevated to HIGH severity

Use cases:

  • Set to true for high-security contexts (admin panels, financial data, healthcare)
  • Set to false for user-generated content that needs flexibility (comments, bios)

Impact on scanning:

  • Increases threat detection sensitivity
  • May reduce false negatives but increases false positives
  • Affects security score calculations
// High-security context
const adminScanner = new Scanner({ strictMode: true });

// User-generated content context
const userScanner = new Scanner({ strictMode: false });

stopOnFirstThreat (boolean, default: false)

Enables early termination on first threat detection.

  • When false: Scans all fields and collects all threats
  • When true: Stops scanning after detecting the first threat

Use cases:

  • Set to true for performance-critical APIs or real-time validation
  • Set to false for comprehensive security reports showing all issues

Impact on scanning:

  • Significantly improves performance when threats exist
  • Reduces response time for high-volume form submissions
  • Trade-off: Users see one threat at a time instead of all issues

Performance comparison:

// Fast: stops at first threat
const fastScanner = new Scanner({ stopOnFirstThreat: true });
// Result time: ~2-5ms for input with threats

// Thorough: collects all threats
const thoroughScanner = new Scanner({ stopOnFirstThreat: false });
// Result time: ~10-20ms for same input

includeValueInResponse (boolean, default: false)

Includes scanned field values in the response.

  • When false: Response contains only threat metadata
  • When true: Response includes original field values

Use cases:

  • Set to true for detailed logging and audit trails
  • Set to false for privacy-sensitive deployments
  • Never enable in untrusted client-side code

Security considerations:

  • Enables detailed debugging and incident analysis
  • Increases response payload size (20-50% larger)
  • Be cautious in production; sensitive data may be logged
// For logging and audit trails
const auditScanner = new Scanner({ includeValueInResponse: true });
// Response includes: { name: 'email', value: 'test@example.com', threats: [...] }

// For privacy (default)
const privateScanner = new Scanner({ includeValueInResponse: false });
// Response includes: { name: 'email', threats: [...] } (no value)

customPatterns (Record<ScannerType, Pattern[]>, default: {})

Extends or overrides threat detection patterns.

Allows adding organization-specific threat patterns or domain-specific rules without losing built-in patterns.

Supported scanner types:

  • "sqlInjection" - SQL injection patterns
  • "noSqlInjection" - NoSQL/MongoDB injection patterns
  • "xss" - Cross-Site Scripting patterns
  • "pathTraversal" - Directory traversal patterns
  • "tokenLeakage" - Sensitive credential patterns

Pattern structure:

interface Pattern {
pattern: RegExp; // Regex to match threats
type: string; // Unique threat identifier
severity: "HIGH" | "MEDIUM" | "LOW";
}

Examples:

// Add custom XSS pattern
const scanner = new Scanner({
customPatterns: {
xss: [
{
pattern: /myCustomFramework\.render\(/gi,
type: 'FRAMEWORK_EXEC',
severity: 'HIGH'
}
]
}
});

// Add custom SQL injection pattern
const scanner = new Scanner({
customPatterns: {
sqlInjection: [
{
pattern: /\bEXEC\b.*\bsp_/gi,
type: 'STORED_PROCEDURE_EXEC',
severity: 'HIGH'
}
]
}
});

// Multiple custom patterns
const scanner = new Scanner({
customPatterns: {
xss: [
{ pattern: /javascript:eval/gi, type: 'EVAL_EXEC', severity: 'HIGH' }
],
pathTraversal: [
{ pattern: /\.\.\./, type: 'TRIPLE_DOT', severity: 'MEDIUM' }
]
}
});

Threat Categories

1. SQL Injection

Detects: UNION SELECT, OR/AND conditions, stacked queries, time-based attacks, SQL comments

const result = scanner.scan([
{ name: 'query', value: "'; UNION SELECT * FROM users; --" }
], 'sqlInjection');

Detected patterns:

  • UNION SELECT joins
  • OR 1=1 conditions
  • SQL comments (--, #, /* */)
  • Stacked queries (;DROP TABLE)
  • Time-based delays (SLEEP, BENCHMARK)
  • Schema probing (information_schema)

2. NoSQL Injection

Detects: MongoDB operators, function injection, array injection, operator injection

const result = scanner.scan([
{ name: 'filter', value: '{"$where": "1==1"}' }
], 'noSqlInjection');

Detected patterns:

  • MongoDB operators ($where, $ne, $regex, etc.)
  • Function definitions in queries
  • Object/array constructor abuse

3. Cross-Site Scripting (XSS)

Detects: Script tags, event handlers, javascript: protocol, data URIs, SVG attacks

const result = scanner.scan([
{ name: 'comment', value: '<img src=x onerror="alert(1)">', type: 'html' }
], 'xss');

Detected patterns:

  • Script tags: <script>, space-separated <s c r i p t>, nested variants
  • Event handlers: onerror=, onclick=, onload=, etc.
  • Protocols: javascript:, vbscript:, data:
  • Dangerous tags: <iframe>, <embed>, <object>, <svg>, etc.
  • Encoded attempts: %3Cscript, &lt;script

4. Path Traversal

Detects: Directory traversal sequences, encoded variants, absolute paths

const result = scanner.scan([
{ name: 'file', value: '../../etc/passwd' }
], 'pathTraversal');

Detected patterns:

  • Directory traversal: ../, ..\, multiple levels
  • Encoded variants: %2e%2e, %c0%af (Unicode normalization)
  • Absolute paths: /etc/, /var/, C:\Windows\
  • Null byte injection: %00, \0

5. Token Leakage

Detects: JWT tokens, API keys, AWS credentials, private keys, database connections

const result = scanner.scan([
{ name: 'header', value: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' }
], 'tokenLeakage');

Detected patterns:

  • JWT tokens: eyJ... patterns
  • AWS credentials: AKIA prefix keys, aws_secret_access_key
  • GitHub tokens: ghp_, gho_ prefixes
  • Stripe keys: sk_live_, pk_live_
  • API keys: Generic api_key= patterns
  • Private keys: PEM formatted keys
  • Database URIs: Connection strings

API Methods

scanAll(fields) - Comprehensive Security Scan

Scans fields against all threat types for complete security analysis.

const result = scanner.scanAll([
{ name: 'email', value: 'user@example.com', type: 'email' },
{
name: 'bio',
value: '<p>Developer</p>',
type: 'html',
allowedTags: ['p', 'br']
}
]);

Parameters:

  • fields (FieldInput[]): Array of fields to scan

Returns: ScanResult - Comprehensive results with security scores

When to use:

  • Initial security analysis requiring all threat types
  • General-purpose form validation
  • When you don't know which threats are most likely

scan(fields, scannerType) - Targeted Threat Detection

Scans fields for a specific threat type to optimize performance.

// Check only for XSS threats
const result = scanner.scan(fields, 'xss');

// Check only for SQL injection
const result = scanner.scan(fields, 'sqlInjection');

// Check only for token leakage
const result = scanner.scan(fields, 'tokenLeakage');

Parameters:

  • fields (FieldInput[]): Array of fields to scan
  • scannerType (ScannerType): One of:
    • 'sqlInjection'
    • 'noSqlInjection'
    • 'xss'
    • 'pathTraversal'
    • 'tokenLeakage'

Returns: ScanResult - Scan result using only the specified scanner

Use cases:

  • Validate user comments for XSS only: scan(comments, 'xss')
  • Check file uploads for path traversal: scan(uploads, 'pathTraversal')
  • Scan database queries for SQL injection: scan(queries, 'sqlInjection')

Throws:

  • Error if scannerType is invalid

scanMultiple(fields, scannerTypes) - Multi-Type Threat Detection

NEW - Scans fields against multiple specified threat types for flexible security control.

// Check only for XSS and SQL injection (skip others)
const result = scanner.scanMultiple(fields, ['xss', 'sqlInjection']);
console.log(`Security Score: ${result.securityScore}`);

Parameters:

  • fields (FieldInput[]): Array of fields to scan
  • scannerTypes (ScannerType[]): Array of threat types to check:
    • 'sqlInjection' - SQL injection detection
    • 'noSqlInjection' - NoSQL injection detection
    • 'xss' - Cross-Site Scripting detection
    • 'pathTraversal' - Directory traversal detection
    • 'tokenLeakage' - Credential leakage detection

Returns: ScanResult - Results with scanner property set to "multiple"

When to use:

  • Check specific threats relevant to your business logic
  • Optimize performance by excluding irrelevant categories
  • Context-aware scanning (different threats for different fields)
  • Reduce false positives from unused scanner types

Examples:

const scanner = new Scanner();

// Check for injection attacks only
const result = scanner.scanMultiple(fields, ['sqlInjection', 'noSqlInjection']);
if (!result.passed) {
result.result.forEach(field => {
if (field.threats.length > 0) {
console.log(`${field.name}: ${field.threats[0].type}`);
}
});
}

// API-specific scanning: SQL and path traversal (skip XSS/tokens)
const apiFields = [
{ name: 'query', value: userQuery, type: 'text' },
{ name: 'filepath', value: userPath, type: 'text' }
];
const result = scanner.scanMultiple(apiFields, ['sqlInjection', 'pathTraversal']);

// HTML content: only check relevant threats
const htmlContent = userBio;
const result = scanner.scanMultiple(
[{ name: 'bio', value: htmlContent, type: 'html' }],
['xss', 'tokenLeakage']
);

Throws:

  • TypeError if scannerTypes is not an array or is empty
  • Error if any scanner type in the array is invalid

scanAsync(fields) - Asynchronous Scanning

Non-blocking version of scanAll() using Promises, ideal for large datasets.

// With async/await
const result = await scanner.scanAsync(largeFieldArray);
console.log(`Scan completed in ${result.duration}ms`);

// With .then()
scanner.scanAsync(fields)
.then(result => console.log('Scan complete:', result))
.catch(error => console.error('Scan error:', error));

Parameters:

  • fields (FieldInput[]): Array of fields to scan

Returns: Promise<ScanResult> - Resolves to scan results

When to use:

  • Scanning 1000+ fields
  • Background security checks
  • Real-time validation in UI threads
  • API endpoints with multiple form submissions

Complete Response Structures

Every Scanner method returns structured data. Here's the complete breakdown of all response types.

ScanResult (Top-Level Response)

The main response object returned by all scanning methods.

interface ScanResult {
securityScore: number; // 0-1 scale (0 = compromised, 1 = secure)
scanner: "all" | "multiple" | ScannerType; // Which scan method was used
passed: boolean; // true if no threats detected
duration: number; // Milliseconds taken to scan
result: FieldResult[]; // Per-field results
}

Example:

{
securityScore: 0.85,
scanner: "all",
passed: false,
duration: 12,
result: [
// FieldResult objects
]
}

Property descriptions:

  • securityScore: Normalized score from 0 to 1

    • 1.0 = No threats detected, completely secure
    • 0.7-0.9 = Minor issues (LOW severity threats)
    • 0.3-0.6 = Moderate issues (MEDIUM/HIGH mix)
    • 0.0-0.3 = Critical threats (multiple HIGH)
    • 0.0 = Multiple critical threats, severely compromised
  • scanner: Indicates which scanning method was used

    • "all" = scanAll() was used (all 5 threat types)
    • "multiple" = scanMultiple() was used with specific types
    • "sqlInjection", "xss", etc. = scan() was used with specific type
  • passed: Quick boolean to check if validation succeeded

    • true = No threats detected in any field
    • false = At least one threat was found
  • duration: Useful for monitoring scanning performance

    • Time in milliseconds from start to finish
    • Helps identify performance bottlenecks
  • result: Array of per-field analysis

    • One FieldResult object per input field
    • Even if field has no threats, an entry exists

FieldResult (Per-Field Response)

Detailed results for each field scanned.

interface FieldResult {
name: string; // Field name/identifier
value?: string; // Original value (only if includeValueInResponse: true)
securityScore: number; // 0-1 score for this field
passed: boolean; // true if no threats in this field
threats: Threat[]; // Array of detected threats
}

Example:

{
name: "email",
securityScore: 1.0,
passed: true,
threats: [],
value: "user@example.com" // Only included if includeValueInResponse: true
}

Property descriptions:

  • name: Matches the name property from input FieldInput

    • Used to identify which field has issues
    • Must be unique within batch for clarity
  • value: Original scanned value (for debugging/logging)

    • Only included if includeValueInResponse: true in config
    • Useful for audit trails and detailed logging
    • Security note: Be careful logging sensitive data
  • securityScore: Field-specific security score (0-1)

  • passed: Shortcut to check if field is secure

    • Equivalent to threats.length === 0
    • Quick way to filter clean vs problematic fields
  • threats: Array of Threat objects (empty if passed)

    • Each object describes a detected security issue
    • Multiple threats possible in single field
    • See Threat structure below

Threat (Individual Threat Details)

Information about each detected security threat.

interface Threat {
type: string; // Threat identifier (e.g., "SCRIPT_TAG")
severity: "HIGH" | "MEDIUM" | "LOW"; // Risk level
pattern: string; // Regex pattern that matched
matched: string; // Exact matched string from input
position: number; // Index position in normalized input
recommendation: string; // How to fix this threat
}

Example:

{
type: "SCRIPT_TAG",
severity: "HIGH",
pattern: "/<\\s*s\\s*[^\\S\\r\\n]*\\s*c.../",
matched: "<script>",
position: 15,
recommendation: "Remove script tags or encode HTML entities; sanitize input"
}

Property descriptions:

  • type: Threat classification for identification

    • Examples: "SCRIPT_TAG", "UNION_SELECT", "JWT_TOKEN"
    • Used to categorize and handle threats programmatically
    • Threat types list available in each threat category section
  • severity: Risk level classification

    • "HIGH" = Critical threat, must be fixed (elevated in strictMode)
    • "MEDIUM" = Important threat, should be fixed (elevated to HIGH in strictMode)
    • "LOW" = Minor threat, nice to fix but not critical
    • Affects security score calculation
  • pattern: The regex pattern that detected this threat

    • Useful for understanding why it matched
    • Can be used for custom filtering
    • Shown as string representation
  • matched: The actual substring that triggered the threat detection

    • Helpful for pinpointing the issue in user input
    • May be percent-decoded or normalized version
    • Can be highlighted in error messages to user
  • position: Character position in the normalized input where threat was found

    • Useful for highlighting errors to users
    • Based on normalized (not original) input
    • First character is position 0
  • recommendation: Actionable advice for remediating this specific threat

    • Different recommendations for different threat types
    • Helps developers fix the underlying issue
    • Examples:
      • For SQL: "Use parameterized queries or prepared statements"
      • For XSS: "Remove script tags or encode HTML entities; sanitize input"
      • For Path Traversal: "Use basename() or validate against whitelist"

FieldInput (Input Format)

The format required when passing fields to Scanner methods.

interface FieldInput {
name: string; // Unique field identifier
value: string; // Content to scan
type?: string; // Field context (optional)
allowedTags?: string[]; // Allowed HTML tags (optional, for type: 'html')
}

Example:

[
{
name: "email",
value: "user@example.com",
type: "email"
},
{
name: "bio",
value: "<p>Developer</p>",
type: "html",
allowedTags: ["p", "strong", "em", "br"]
},
{
name: "comment",
value: "Nice article!",
type: "text"
}
]

Property descriptions:

  • name (required): Unique identifier for the field

    • Used in response to identify which field has threats
    • Examples: "email", "comment", "bio"
    • Should be unique within a batch to prevent confusion
  • value (required): The actual content to scan

    • Any string, including empty strings
    • Will be normalized before pattern matching
    • Should contain user input or untrusted content
  • type (optional): Context about the field

    • "text" - Plain text (most common)
    • "email" - Email address
    • "html" - HTML content (enables allowedTags)
    • "password" - Password field
    • "url" - URL/URI
    • Others: "textarea", "tel", "number", etc.
    • Used to make scanning context-aware
  • allowedTags (optional): HTML tags to allow

    • Only effective when type: "html"
    • Examples: ["p", "strong", "em", "br", "a"]
    • Script and event handlers are NEVER allowed, even if listed
    • Use to permit safe tags while blocking dangerous ones

ScannerConfig (Configuration Options)

Configuration passed to the Scanner constructor.

interface ScannerConfig {
strictMode?: boolean;
stopOnFirstThreat?: boolean;
includeValueInResponse?: boolean;
customPatterns?: Partial<Record<ScannerType, Pattern[]>>;
}

All properties with defaults:

{
strictMode: false, // default
stopOnFirstThreat: false, // default
includeValueInResponse: false, // default
customPatterns: {} // default
}

See the Configuration section above for detailed parameter explanations.


Pattern (Custom Pattern Format)

Format for defining custom threat detection patterns.

interface Pattern {
pattern: RegExp; // Regex to match threats
type: string; // Unique threat identifier
severity: "HIGH" | "MEDIUM" | "LOW";
}

Example:

{
pattern: /myCustomFramework\.render\(/gi,
type: "FRAMEWORK_EXEC",
severity: "HIGH"
}

Property descriptions:

  • pattern: Regular expression to match

    • Uses JavaScript RegExp syntax
    • Should use g (global) flag to find all matches
    • Should use i (case-insensitive) for most patterns
    • More specific patterns = fewer false positives
  • type: Identifier for this specific threat

    • Used in Threat responses to identify the threat
    • Should be descriptive and unique
    • Examples: "FRAMEWORK_EXEC", "CUSTOM_XSS", "API_KEY_LEAK"
  • severity: Risk classification

    • "HIGH" = Critical, block immediately
    • "MEDIUM" = Important, should address
    • "LOW" = Minor, nice to know

Response Examples

Example 1: Clean Input

All fields pass validation:

const result = scanner.scanAll([
{ name: "email", value: "user@example.com", type: "email" },
{ name: "comment", value: "Great article!", type: "text" }
]);

// Response:
{
securityScore: 1.0,
scanner: "all",
passed: true,
duration: 5,
result: [
{
name: "email",
securityScore: 1.0,
passed: true,
threats: []
},
{
name: "comment",
securityScore: 1.0,
passed: true,
threats: []
}
]
}

Example 2: XSS Detected

One field contains XSS:

const result = scanner.scanAll([
{
name: "comment",
value: "<img src=x onerror='alert(1)'>",
type: "html",
allowedTags: ["p", "br"]
}
]);

// Response:
{
securityScore: 0.4,
scanner: "all",
passed: false,
duration: 8,
result: [
{
name: "comment",
securityScore: 0.6,
passed: false,
threats: [
{
type: "EVENT_HANDLER",
severity: "HIGH",
pattern: "/\\bon\\w+\\s*=\\s*(\".*?\"|'.*?'|[^\\s>]+)/gi",
matched: "onerror='alert(1)'",
position: 10,
recommendation: "Remove inline event handlers or sanitize attributes"
}
]
}
]
}

Example 3: Multiple Threats in One Field

Field with multiple issues:

const result = scanner.scanAll([
{
name: "query",
value: "'; DROP TABLE users; -- <script>alert(1)</script>",
type: "text"
}
]);

// Response:
{
securityScore: 0.0,
scanner: "all",
passed: false,
duration: 12,
result: [
{
name: "query",
securityScore: 0.0,
passed: false,
threats: [
{
type: "STACKED_QUERY",
severity: "HIGH",
pattern: "/;\\s*(DROP|DELETE|UPDATE|INSERT|ALTER|CREATE)\\b/gi",
matched: "; DROP",
position: 1,
recommendation: "Disable multiple statement execution"
},
{
type: "SCRIPT_TAG",
severity: "HIGH",
pattern: "/<\\s*s\\s*c\\s*r\\s*i\\s*p\\s*t[^>]*>[\\s\\S]*?<\\/script>/gi",
matched: "<script>alert(1)</script>",
position: 30,
recommendation: "Remove script tags or encode HTML entities; sanitize input"
}
]
}
]
}

Example 4: Using Targeted scan()

Scanning only for SQL injection:

const result = scanner.scan(
[{ name: "query", value: "SELECT * FROM users WHERE id=1 OR 1=1" }],
"sqlInjection"
);

// Response:
{
securityScore: 0.4,
scanner: "sqlInjection",
passed: false,
duration: 6,
result: [
{
name: "query",
securityScore: 0.6,
passed: false,
threats: [
{
type: "OR_CONDITION",
severity: "HIGH",
pattern: "/(\\bOR\\b\\s+['\"]*(\\d+)['\"]*(\\s*=\\s*)['\"]*(\\d+))/gi",
matched: "OR 1=1",
position: 38,
recommendation: "Validate input and use parameterized queries"
}
]
}
]
}

Example 5: Using scanMultiple()

Scanning for specific threats only:

const result = scanner.scanMultiple(
[
{ name: "file", value: "../../etc/passwd" },
{ name: "jwt", value: "eyJhbGciOiJIUzI1NiJ9..." }
],
["pathTraversal", "tokenLeakage"]
);

// Response:
{
securityScore: 0.2,
scanner: "multiple",
passed: false,
duration: 9,
result: [
{
name: "file",
securityScore: 0.4,
passed: false,
threats: [
{
type: "DIRECTORY_TRAVERSAL",
severity: "HIGH",
pattern: "/\\.\\.[\\/\\\\]/g",
matched: "../",
position: 0,
recommendation: "Use basename() or validate against whitelist"
}
]
},
{
name: "jwt",
securityScore: 0.4,
passed: false,
threats: [
{
type: "JWT_TOKEN",
severity: "HIGH",
pattern: "/eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}/g",
matched: "eyJhbGciOiJIUzI1NiJ9...",
position: 0,
recommendation: "Remove JWT token from input"
}
]
}
]
}

Input Normalization

The scanner applies a 8-step normalization pipeline to defeat obfuscation:

  1. Trim - Remove leading/trailing whitespace
  2. Remove invisible characters - Zero-width, soft hyphens, BOMs, RTL markers
  3. Percent-decode - Convert %XX sequences to characters
  4. HTML entity decode - Convert &#XX; and &lt; to characters
  5. JavaScript escape decode - Convert \uXXXX and \xXX to characters
  6. Null byte removal - Remove \0, %00, &#0; variants
  7. Tag whitespace normalization - Convert < s c r i p t > to <script>
  8. Whitespace collapse - Convert multiple spaces to single space

Example - Multi-layer obfuscation:

Input:  "%3C%73%63%72%69%70%74%3E%20%61%6C%65%72%74%28%31%29%20%3C%2F%73%63%72%69%70%74%3E"
Step 1: "%3C%73%63%72%69%70%74%3E%20alert(1)%20%3C%2F%73%63%72%69%70%74%3E"
Step 2: "<script> alert(1) </script>"
Step 3: (HTML entities - no change)
Step 4: (JS escapes - no change)
Step 5: "<script>alert(1)</script>"
Result: Detected as XSS!

Characters removed (invisible):

  • Soft hyphen: \u00AD
  • Zero-width space: \u200B
  • Zero-width joiner: \u200D
  • Zero-width non-joiner: \u200C
  • Word joiner: \u2060
  • Byte order mark: \uFEFF
  • And 30+ other formatting characters

Security Score Calculation

Scores are calculated on a scale of 0 (compromised) to 1.0 (secure).

Penalty per threat:

  • HIGH severity: -0.4
  • MEDIUM severity: -0.2
  • LOW severity: -0.1

Examples:

// 1 HIGH threat: 1.0 - 0.4 = 0.6
// 2 MEDIUM threats: 1.0 - (0.2 × 2) = 0.6
// 1 HIGH + 2 MEDIUM: 1.0 - 0.4 - 0.4 = 0.2
// 3 HIGH threats: 1.0 - (0.4 × 3) = -0.2 → capped at 0.0

Interpreting scores:

  • 1.0 - Completely secure, no threats
  • 0.7-0.9 - Minor issues detected (LOW threats)
  • 0.3-0.6 - Moderate threats (MEDIUM/HIGH mix)
  • 0.0-0.3 - Critical threats (multiple HIGH)
  • 0.0 - Severe compromise, multiple critical threats

Best Practices

  1. Choose appropriate strictness - Balance security vs. false positives
  2. Use targeted scanning when possible - Improves performance
  3. Validate on server side - Never rely solely on client-side scanning
  4. Log threats for audit trails - Enable includeValueInResponse for detailed logging
  5. Keep patterns updated - Review custom patterns quarterly
  6. Handle false positives gracefully - Provide clear error messages
  7. Combine with other defenses - Scanner is one layer in defense-in-depth
  8. Test with real attack payloads - Verify your configuration actually blocks threats

Common Questions

Q: Can I use Scanner on the client side?
A: Yes, but it's not a complete solution. Client-side scanning is easily bypassed. Always validate on the server side too.

Q: Should I enable strictMode for user comments?
A: No, it causes false positives. Reserve strictMode: true for admin areas and sensitive operations.

Q: How do I add custom threat patterns?
A: Use the customPatterns config option. Create regex patterns matching your specific threats.

Q: Is the Scanner encoding-aware?
A: Yes! It decodes URL encoding, HTML entities, JavaScript escapes, and removes zero-width characters before pattern matching.

Q: Does Scanner protect against all XSS attacks?
A: It catches common XSS patterns, but isn't foolproof. Always sanitize output with libraries like DOMPurify on the frontend.

Q: What's the difference between scan(), scanAll(), and scanMultiple()?
A: scan() checks one threat type, scanAll() checks all five, scanMultiple() checks a specific subset you choose.

Q: When should I use scanMultiple()?
A: Use it when you know which threats are relevant (e.g., only SQL for database queries, only XSS for HTML content).


See Also