@browsertotal/scanner
v1.0.9
Published
Scan URLs and extensions using BrowserTotal.com
Maintainers
Readme
Why BrowserTotal Scanner?
Real Browser Analysis - Unlike static analysis tools, BrowserTotal Scanner launches a real browser instance to analyze URLs and extensions exactly as they would execute in a user's environment. This catches threats that only activate in actual browser contexts.
Dynamic Behavior Tracing - Every network request, DOM manipulation, cookie access, and API call is traced and recorded. See what extensions and websites actually do, not just what their code looks like.
Sandboxed Execution - All analysis runs in an isolated, sandboxed browser environment. Test suspicious URLs and extensions safely without risking your system.
AI-Powered Threat Detection - Combines runtime behavior analysis with LLM-powered code review to identify obfuscated malware, data exfiltration, and sophisticated supply chain attacks.
Multi-Platform Coverage - Scan browser extensions (Chrome, Firefox, Edge, Safari, Opera, Brave), IDE plugins (VS Code, JetBrains), and packages (npm, PyPI, WordPress) - all through a unified API.
This package uses Puppeteer to automate browser interactions with BrowserTotal's analysis tools. It leverages a custom event system (#automationEvent=true) to receive complete scan results including AI/LLM analysis.
Supported Platforms
| Platform | Method | Description |
|----------|--------|-------------|
| URLs | scanUrl() | Scan any URL for security threats |
| Chrome | scanExtension() | Chrome Web Store extensions |
| Firefox | scanExtension() | Firefox Add-ons |
| Edge | scanExtension() | Microsoft Edge Add-ons |
| Opera | scanExtension() | Opera Add-ons |
| Safari | scanExtension() | Safari Extensions |
| Brave | scanExtension() | Brave Extensions |
| VS Code | scanVSCodeExtension() | Visual Studio Marketplace extensions |
| Open VSX | scanOpenVSXExtension() | Open VSX Registry extensions |
| JetBrains | scanJetBrainsPlugin() | IntelliJ, PyCharm, WebStorm plugins |
| npm | scanNpmPackage() | npm packages |
| PyPI | scanPyPIPackage() | Python packages |
| WordPress | scanWordPressPlugin() | WordPress plugins |
| Hugging Face | scanHuggingFace() | Hugging Face models/spaces |
| AppSource | scanAppSourceAddin() | Microsoft AppSource add-ins |
| PowerShell | scanPowerShellModule() | PowerShell Gallery modules |
| Salesforce | scanSalesforceApp() | Salesforce AppExchange apps |
Installation
npm install @browsertotal/scannerUsage
Scanning URLs
import { BrowserTotalScanner } from '@browsertotal/scanner';
const scanner = new BrowserTotalScanner();
const result = await scanner.scanUrl('https://example.com');
console.log(result.status); // 'safe' | 'suspicious' | 'malicious' | 'unknown' | 'error'
console.log(result.threats);
console.log(result.raw); // Full analysis data including LLM results
await scanner.close();Scanning Browser Extensions
import { BrowserTotalScanner } from '@browsertotal/scanner';
const scanner = new BrowserTotalScanner();
// Chrome extension
const chromeResult = await scanner.scanExtension('cjpalhdlnbpafiamejdnhcphjbkeiagm', 'chrome');
// Firefox add-on
const firefoxResult = await scanner.scanExtension('ublock-origin', 'firefox');
// Edge extension
const edgeResult = await scanner.scanExtension('extension-id', 'edge');
await scanner.close();Scanning VS Code Extensions
import { BrowserTotalScanner } from '@browsertotal/scanner';
const scanner = new BrowserTotalScanner();
// VS Code Marketplace extension (publisher.extension-name format)
const result = await scanner.scanVSCodeExtension('ms-python.python');
console.log(result.name);
console.log(result.status);
console.log(result.permissions);
await scanner.close();Scanning JetBrains Plugins
import { BrowserTotalScanner } from '@browsertotal/scanner';
const scanner = new BrowserTotalScanner();
// JetBrains plugin by ID
const result = await scanner.scanJetBrainsPlugin('7495'); // Rainbow Brackets
console.log(result.status);
await scanner.close();Scanning npm Packages
import { BrowserTotalScanner } from '@browsertotal/scanner';
const scanner = new BrowserTotalScanner();
const result = await scanner.scanNpmPackage('lodash');
console.log(result.status);
console.log(result.version);
console.log(result.dependencies);
await scanner.close();Scanning PyPI Packages
import { BrowserTotalScanner } from '@browsertotal/scanner';
const scanner = new BrowserTotalScanner();
const result = await scanner.scanPyPIPackage('requests');
console.log(result.status);
console.log(result.version);
await scanner.close();Scanning WordPress Plugins
import { BrowserTotalScanner } from '@browsertotal/scanner';
const scanner = new BrowserTotalScanner();
const result = await scanner.scanWordPressPlugin('akismet');
console.log(result.status);
await scanner.close();Generic Platform Scanning
Use scanByPlatform() for dynamic platform selection:
import { BrowserTotalScanner } from '@browsertotal/scanner';
const scanner = new BrowserTotalScanner();
// Scan any platform dynamically
const result = await scanner.scanByPlatform('lodash', 'npmjs');
const result2 = await scanner.scanByPlatform('extension-id', 'chrome');
const result3 = await scanner.scanByPlatform('ms-python.python', 'vscode');
await scanner.close();Convenience Functions
For one-off scans without managing the scanner lifecycle:
import {
scanUrl,
scanExtension,
scanVSCodeExtension,
scanJetBrainsPlugin,
scanNpmPackage,
scanPyPIPackage,
scanWordPressPlugin
} from '@browsertotal/scanner';
// One-off URL scan
const urlResult = await scanUrl('https://example.com');
// One-off browser extension scan
const extResult = await scanExtension('extension-id', 'chrome');
// One-off VS Code extension scan
const vscodeResult = await scanVSCodeExtension('ms-python.python');
// One-off npm package scan
const npmResult = await scanNpmPackage('express');
// One-off PyPI package scan
const pypiResult = await scanPyPIPackage('django');Progress Tracking
import { BrowserTotalScanner } from '@browsertotal/scanner';
const scanner = new BrowserTotalScanner();
const result = await scanner.scanNpmPackage('express', (progress) => {
console.log(`[${progress.phase}] ${progress.message}`);
});
await scanner.close();Configuration Options
import { BrowserTotalScanner } from '@browsertotal/scanner';
const scanner = new BrowserTotalScanner({
headless: true, // Run browser in headless mode (default: true)
timeout: 120000, // Timeout in milliseconds (default: 420000)
waitForResults: true, // Wait for scan to complete (default: true)
disableAI: true, // Skip AI/LLM analysis for faster scans (default: true)
userDataDir: '/tmp/browser', // Custom browser profile directory
});How It Works
The scanner uses a special automation mode that:
- Appends
#automationEvent=trueto scan URLs - BrowserTotal's UI detects this parameter and dispatches a
scan_resultcustom event when analysis completes - Puppeteer captures this event to get the full scan results
This approach ensures you get the complete analysis data, including:
- Static analysis results
- LLM/AI analysis results
- Risk scores and threat assessments
- Permission analysis (for extensions)
- Dependency analysis (for packages)
- Vulnerability findings
API Reference
BrowserTotalScanner
Constructor Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| headless | boolean | true | Run browser in headless mode |
| timeout | number | 420000 | Timeout in milliseconds |
| waitForResults | boolean | true | Wait for scan results before returning |
| disableAI | boolean | true | Skip AI/LLM analysis for faster scans |
| userDataDir | string | undefined | Custom browser profile directory |
Methods
URL Scanning
scanUrl(url: string, onProgress?: ProgressCallback): Promise<UrlScanResult>
Browser Extensions
scanExtension(extensionId: string, store?: BrowserStore, onProgress?: ProgressCallback): Promise<ExtensionScanResult>
IDE Extensions
scanVSCodeExtension(extensionId: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>scanOpenVSXExtension(extensionId: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>scanJetBrainsPlugin(pluginId: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>
Package Managers
scanNpmPackage(packageName: string, onProgress?: ProgressCallback): Promise<PackageScanResult>scanPyPIPackage(packageName: string, onProgress?: ProgressCallback): Promise<PackageScanResult>scanPowerShellModule(moduleName: string, onProgress?: ProgressCallback): Promise<PackageScanResult>
Other Platforms
scanWordPressPlugin(pluginSlug: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>scanHuggingFace(modelId: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>scanAppSourceAddin(addinId: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>scanSalesforceApp(appId: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>
Generic
scanByPlatform(identifier: string, platform: Platform | BrowserStore, onProgress?: ProgressCallback): Promise<ExtensionScanResult | PackageScanResult>
Lifecycle
close(): Promise<void>- Closes the browser instance
Types
BrowserStore
type BrowserStore = 'chrome' | 'firefox' | 'edge' | 'opera' | 'safari' | 'brave';Platform
type Platform =
| 'vscode'
| 'openvsx'
| 'jetbrains'
| 'npmjs'
| 'pypi'
| 'wordpress'
| 'huggingface'
| 'appsource'
| 'powershellgallery'
| 'salesforce';UrlScanResult
interface UrlScanResult {
url: string;
status: 'safe' | 'suspicious' | 'malicious' | 'unknown' | 'error';
score?: number;
threats?: ThreatInfo[];
categories?: string[];
scanUrl: string;
timestamp: Date;
raw?: Record<string, unknown>; // Full scan data including LLM results
}ExtensionScanResult
interface ExtensionScanResult {
extensionId: string;
name?: string;
status: 'safe' | 'suspicious' | 'malicious' | 'unknown' | 'error';
score?: number;
permissions?: string[];
threats?: ThreatInfo[];
scanUrl: string;
timestamp: Date;
raw?: Record<string, unknown>; // Full scan data including LLM results
}PackageScanResult
interface PackageScanResult {
packageName: string;
platform: string;
name?: string;
version?: string;
status: 'safe' | 'suspicious' | 'malicious' | 'unknown' | 'error';
score?: number;
dependencies?: Record<string, string>;
threats?: ThreatInfo[];
scanUrl: string;
timestamp: Date;
raw?: Record<string, unknown>; // Full scan data including LLM results
}Requirements
- Node.js 18+
- Puppeteer (installed automatically)
