@skydevlab/securejs
v0.1.0
Published
Secure-by-default browser utilities for JavaScript.
Maintainers
Readme
SecureJS
Secure-by-default browser utilities for JavaScript.
SecureJS (@skydevlab/securejs by SkyDevLab) is a lightweight, framework-independent TypeScript library providing composable, secure-by-default browser utilities. It helps developers avoid common browser-side security mistakes—such as Open Redirects, javascript: XSS, Reverse Tabnabbing, prototype pollution in web storage, clipboard bombs, and wildcard postMessage leaks.
npm install @skydevlab/securejsWorks Seamlessly With
SecureJS has zero runtime dependencies on any frontend framework. It works across modern and legacy web stacks:
- Vanilla JavaScript & TypeScript
- React & Next.js
- Vue & Nuxt
- Angular
- Svelte & SvelteKit
- jQuery
- ASP.NET MVC & ASP.NET Core Razor Pages
- Any browser-based web application
Core Philosophy
"SecureJS helps developers reduce common browser-side security mistakes."
SecureJS NEVER claims to secure your entire application. True application security requires defense-in-depth across server controls, browser headers, and strict development practices.
- Secure by Default: Safe fallbacks over surprising mutations or silent failures.
- Framework Agnostic: Pure browser/DOM utilities with zero framework baggage.
- TypeScript First: Written in strict TypeScript with comprehensive
.d.tsdeclaration maps and source maps. - Modular & Tree-Shakeable: Import only what you need, either from the root or via dedicated subpaths (
@skydevlab/securejs/url). - No Global Monkey-Patching: Never alters native prototypes (
window,Document,Element.prototype,fetch) by default. - Actionable Dev Warnings: Opt-in development security checker that identifies dangerous inputs without logging sensitive user data.
Quick Start
import { safeURL, safeExternalLink, safeStorage } from "@skydevlab/securejs";
// 1. Sanitize untrusted URLs
const userLink = safeURL(userInput); // returns safe URL string or null
// 2. Safe external link props (mitigating Reverse Tabnabbing)
const linkProps = safeExternalLink(userInput);
// -> { href: "https://...", rel: "noopener noreferrer", target: "_blank", isExternal: true }
// 3. Hardened storage with prototype pollution protection
safeStorage.setItem("user-settings", { theme: "dark" });
const settings = safeStorage.getItem("user-settings");Table of Contents
Modular Subpath Imports
SecureJS supports modern package exports. If bundle size is critical, you can import individual modules directly:
import { safeURL } from "@skydevlab/securejs/url";
import { safeRedirect } from "@skydevlab/securejs/redirect";
import { isAllowedOrigin } from "@skydevlab/securejs/origin";
import { safeExternalLink } from "@skydevlab/securejs/links";
import { safeHTML } from "@skydevlab/securejs/html";
import { safeSetAttribute } from "@skydevlab/securejs/attributes";
import { safePostMessage } from "@skydevlab/securejs/messaging";
import { safePaste } from "@skydevlab/securejs/clipboard";
import { validateFile } from "@skydevlab/securejs/files";
import { safeStorage } from "@skydevlab/securejs/storage";
import { enableDevWarnings } from "@skydevlab/securejs/warnings";API Reference
1. URL Security
Protects against XSS vectors via dangerous schemes (javascript:, data:, vbscript:, blob:), null bytes, and protocol-relative bypasses.
import { safeURL, isSafeURL } from "@skydevlab/securejs";
// Returns sanitized URL string or null
safeURL("https://example.com"); // "https://example.com/"
safeURL("javascript:alert(1)"); // null
safeURL("//attacker.com"); // null (blocked protocol-relative bypass)
// Advanced Configuration
const clean = safeURL(untrustedInput, {
allowedProtocols: ["https:"], // Restrict protocols (default: ['https:', 'http:'])
allowedOrigins: ["https://example.com", "https://*.example.com"], // Restrict origins
allowRelative: true, // Allow relative URLs (default: false)
fallback: "/error", // Fallback returned on failure (default: null)
});
// Boolean check
if (isSafeURL(untrustedInput)) {
// Safe to proceed
}2. Safe Redirect
Prevents Open Redirect vulnerabilities (CWE-601) where untrusted destinations deceive users into navigating to malicious external sites.
import { safeRedirect } from "@skydevlab/securejs";
const result = safeRedirect(redirectParam, {
allowRelative: true, // Allow safe relative paths like /dashboard (default: true)
allowedOrigins: ["https://auth.company.com"], // Whitelist external redirect destinations
action: "replace", // Optional: 'assign' | 'replace' | 'none'
fallback: "/home",
});
if (result.ok) {
// Automatically navigates window.location if action is set, or manually:
result.execute();
} else {
console.error("Open redirect blocked:", result.reason);
}3. Origin Validation
Provides strict WHATWG origin matching. Protects against common substring confusion attacks (example.com.attacker.com or fake-example.com).
import { isAllowedOrigin, validateOrigin } from "@skydevlab/securejs";
const allowed = isAllowedOrigin(window.location.origin, {
allowedOrigins: [
"https://example.com",
"https://*.example.com", // RFC wildcard subdomain matching
/^https:\/\/app-[a-z]+\.example\.com$/, // Regular expression
(origin) => origin.startsWith("https://trusted-"), // Custom predicate
],
});
// Detailed diagnostic inspection
const status = validateOrigin(incomingOrigin, { allowedOrigins: ["https://example.com"] });
if (!status.valid) {
console.warn("Origin rejected because:", status.reason);
}4. External Links
Prepares safe HTML attributes for external links (<a>), mitigating Reverse Tabnabbing by enforcing rel="noopener noreferrer".
import { safeExternalLink } from "@skydevlab/securejs";
// React example:
const linkProps = safeExternalLink(userUrl);
return linkProps ? <a {...linkProps}>Visit Link</a> : null;
// Vanilla JS:
const props = safeExternalLink(userUrl);
if (props) {
linkEl.href = props.href;
linkEl.rel = props.rel; // "noopener noreferrer" if external
if (props.target) linkEl.target = props.target; // "_blank" if external
}5. HTML Sanitization
Integrates enterprise-grade HTML sanitization powered by DOMPurify with secure, defense-in-depth defaults.
import { safeHTML } from "@skydevlab/securejs";
// Strips scripts, event handlers, iframes, styles, and dangerous protocols
const cleanHTML = safeHTML(untrustedUserContent);
element.innerHTML = cleanHTML;
// Custom overrides
const customClean = safeHTML(untrustedUserContent, {
allowedTags: ["b", "i", "strong", "em", "p"],
allowDataURI: false, // Disallows data:* URIs in src attributes (default: false)
});6. Attribute Handling
Provides safe DOM attribute assignment. Blocks on* inline event handlers (onclick, onerror), dangerous attributes (srcdoc), and sanitizes URL-valued attributes (href, src).
Why
safeSetAttributeinstead of raw string interpolation? A generic string functionsafeAttribute(name, value)creates a false sense of security because raw HTML strings depend heavily on surrounding quotes and contexts.safeSetAttributeoperates directly on DOM elements with strict contracts.
import { safeSetAttribute, validateAttributeName } from "@skydevlab/securejs";
const btn = document.createElement("button");
safeSetAttribute(btn, "data-id", "user-123"); // true
safeSetAttribute(btn, "onclick", "alert(1)"); // false (rejected!)
safeSetAttribute(btn, "srcdoc", "evil"); // false (rejected!)
const link = document.createElement("a");
safeSetAttribute(link, "href", "javascript:alert(1)"); // false (rejected!)
safeSetAttribute(link, "href", "https://example.com"); // true7. postMessage Security
Protects cross-window messaging from eavesdropping by enforcing strict destination origins and disallowing wildcard "*" targets.
import { safePostMessage, validateMessageOrigin } from "@skydevlab/securejs";
// 1. Sending: Disallows wildcard '*' by default
safePostMessage(iframeEl.contentWindow, { token: "secret" }, {
targetOrigin: "https://trusted-partner.com", // Required
});
// 2. Receiving: Validates origin and optional payload schema
window.addEventListener("message", (event) => {
const isValid = validateMessageOrigin(event, {
allowedOrigins: ["https://trusted-partner.com"],
validatePayload: (data): data is { status: string } =>
typeof data === "object" && data !== null && "status" in data,
});
if (!isValid) return; // Discard untrusted message
handleMessage(event.data);
});8. Clipboard / Paste Security
Sanitizes pasted text by stripping hidden ASCII control characters, neutralizing Trojan Source bidirectional override characters (\u202E), and truncating oversized payloads to mitigate clipboard bomb DoS.
import { safePaste } from "@skydevlab/securejs";
inputElement.addEventListener("paste", (event) => {
event.preventDefault();
const result = safePaste(event, {
maxLength: 50_000, // Max character limit
stripControlChars: true, // Strips ASCII 0x00-0x1F (preserves \n, \t)
stripBidiOverrides: true, // Neutralizes RLO/LRO Trojan Source overrides
});
insertText(result.text);
});9. File & Filename Validation
Client-side file validation to improve user experience and catch spoofing attempts before uploading.
[!IMPORTANT] Client-side file validation is for UX and defense-in-depth only. It does NOT replace server-side validation, MIME sniffing, virus scanning, and sandboxing.
import { validateFile, sanitizeFileName } from "@skydevlab/securejs";
// 1. File Validation
const validation = validateFile(fileInput.files[0], {
maxSizeBytes: 5 * 1024 * 1024, // 5MB
minSizeBytes: 1, // Disallow empty files
allowedTypes: ["image/png", "image/jpeg"],
allowedExtensions: ["png", "jpg", "jpeg"],
enforceMimeExtensionConsistency: true, // Catches malware disguised as photo.png
});
if (!validation.valid) {
alert(validation.errors[0].message);
}
// 2. Filename Sanitization (cross-platform, stripping ../ and Windows reserved device names)
const safeName = sanitizeFileName("../../user<upload>.pdf.exe");
// -> "user-upload.pdf.exe"10. Safe Web Storage
Hardened wrapper around localStorage and sessionStorage. Protects against Prototype Pollution by stripping __proto__, constructor, and prototype keys during JSON deserialization. Gracefully handles QuotaExceededError and disabled storage (private browsing mode).
[!CAUTION] Web storage is unencrypted and accessible to any script on your origin. NEVER store passwords or cryptographic private keys in localStorage.
import { safeStorage, createSafeStorage } from "@skydevlab/securejs";
// Default pre-configured instance wrapping localStorage
safeStorage.setItem("user", { name: "Alice", role: "admin" });
const user = safeStorage.getItem("user");
// Custom scoped storage instance
const sessionStore = createSafeStorage("session", {
prefix: "app:v1:", // Automatic key namespacing
preventPrototypePollution: true, // Default true
onError: (error, key, op) => {
console.error(`Storage ${op} failed for key "${key}"`, error);
},
});11. Development Warnings
Opt-in diagnostic assistant that reports actionable security warnings in development console without leaking sensitive user data.
import { enableDevWarnings } from "@skydevlab/securejs";
if (process.env.NODE_ENV === "development") {
enableDevWarnings();
}What SecureJS Does NOT Replace
SecureJS is designed to complement existing security standards, not replace them. SecureJS does NOT replace:
| Mechanism | Why It Is Still Required |
| --------- | ------------------------- |
| Content Security Policy (CSP) | Only a strict CSP enforced by the browser can neutralize inline script execution and restrict network exfiltration. |
| Server-Side Validation | Any client-side check can be bypassed by an attacker submitting direct HTTP requests. |
| Trusted Types | Trusted Types enforce browser-level compile-time guarantees for sink injection. |
| HTTPS & Secure Cookies | Transport encryption and HttpOnly; Secure; SameSite cookies are required to protect data in transit and session tokens. |
| Authentication & Authorization | Access controls, password hashing, and role checks must be enforced on the server. |
| Dependency Auditing | Regular npm package scanning (npm audit) is required to prevent supply chain attacks. |
Package Bundle Size & Footprint
SecureJS is compiled with modern ES modules, full tree-shaking support, and zero framework runtime dependencies:
- Root bundle: ~9.5 KB gzipped (includes all modules + DOMPurify)
- Subpath imports:
@skydevlab/securejs/url: ~1.4 KB gzipped@skydevlab/securejs/redirect: ~1.6 KB gzipped@skydevlab/securejs/storage: ~1.2 KB gzipped@skydevlab/securejs/files: ~1.8 KB gzipped@skydevlab/securejs/links: ~1.5 KB gzipped
Contributing
We welcome contributions! Please review CONTRIBUTING.md for development setup, testing requirements, and pull request guidelines.
Security Policy
For vulnerability reporting, please see SECURITY.md.
License
MIT © SkyDevLab
