Trend Micro's APIs target enterprise security products requiring paid subscriptions — they are not available to individual developers. For practical security scanning in Bolt.new apps, use VirusTotal's free API (4 lookups/minute) for file and URL scanning, Snyk's API for dependency vulnerability scanning, or the Have I Been Pwned API for breach detection. All three have free tiers and work via Next.js API routes in Bolt.
Security APIs for Bolt.new: Practical Alternatives to Enterprise Platforms
Trend Micro is an enterprise cybersecurity vendor. Their API surfaces — Trend Micro Cloud One, Vision One, and Apex Central — are designed for corporate IT teams managing thousands of endpoints, containers, and cloud workloads. Accessing these APIs requires an enterprise subscription that starts at thousands of dollars per year and involves a sales process. There is no self-service developer tier, no free trial API key, and no sandbox environment for independent developers. If your organization already has a Trend Micro enterprise license, contact your account team for API access documentation specific to your subscription tier.
For the vast majority of Bolt developers building apps that need security features, the practical options are the purpose-built developer APIs from VirusTotal, Snyk, and similar services. VirusTotal (owned by Google) scans files and URLs against 70+ antivirus engines and threat intelligence feeds, with a free API tier allowing 4 lookups per minute. Snyk is the industry standard for software composition analysis — scanning npm, PyPI, Maven, and other package manifests for known vulnerabilities — with a free tier of 200 tests per month. Have I Been Pwned (HIBP) checks whether an email address or password hash appears in known data breach databases, with a free API for email checks.
These APIs cover the security use cases most relevant to Bolt apps: checking user-uploaded files for malware before processing, scanning URLs before redirecting users, detecting compromised credentials at login, and monitoring your own project's dependencies for CVEs. They integrate cleanly via Next.js API routes, work with Bolt's WebContainer for outbound calls, and require no enterprise procurement process to start using.
Integration method
Trend Micro's APIs require enterprise-level subscriptions and are not practically accessible to individual Bolt developers. This guide covers the practical alternatives: VirusTotal for file and URL scanning (free tier: 4 requests/minute), Snyk for open-source vulnerability scanning (free tier: 200 tests/month), and Have I Been Pwned for breach checking (free API). All integrate via Next.js API routes that proxy calls from your Bolt app.
Prerequisites
- A VirusTotal free API key from virustotal.com/gui/my-apikey (requires free account registration)
- Optionally: a Snyk account with API token from app.snyk.io/account (free tier: 200 tests/month)
- Have I Been Pwned email API key from haveibeenpwned.com/API/Key (paid, $3.50/month for email checks)
- A Next.js project in Bolt (all security APIs require server-side proxy routes to protect API keys)
- Understanding that Trend Micro's enterprise APIs require a paid enterprise subscription unavailable to individual developers
Step-by-step guide
Set up VirusTotal URL and file scanning
Set up VirusTotal URL and file scanning
VirusTotal provides two main scanning operations relevant to Bolt apps: URL analysis and file analysis. Both use the same API key and the same base pattern — submit content for scanning, then retrieve the analysis report. Get your free VirusTotal API key by creating an account at virustotal.com and visiting the API key page in your profile. The free tier allows 4 requests per minute and 500 requests per day. This is sufficient for on-demand scanning in a small application but not for batch processing. For URL scanning, the VirusTotal workflow is: POST the URL to /api/v3/urls to submit it for analysis, which returns an analysis ID. Then GET /api/v3/analyses/{id} to retrieve the report. URL analyses are often available immediately if the URL was recently scanned — check the status field in the response. For file scanning, POST the file binary to /api/v3/files, retrieve the analysis ID, and poll the analysis endpoint until status is 'completed'. File analyses can take 30-60 seconds for first-time submissions. Create a Next.js API route that abstracts the VirusTotal two-step workflow. Your React components call one endpoint that handles both submission and result retrieval, returning a clean summary: the number of antivirus engines that flagged the content, the total engines scanned, and the threat categories detected. Note: VirusTotal file scanning via the API submits the file to VirusTotal's public database. All scanned files are visible to VirusTotal's community members. Do not scan confidential documents or files containing personal data through the public VirusTotal API. For confidential file scanning, VirusTotal Enterprise is required — another enterprise-tier product.
Create a Next.js API route at /api/security/check-url that accepts a POST with a url field. Use the VirusTotal v3 API to scan the URL: first POST to https://www.virustotal.com/api/v3/urls with the URL encoded as base64url, then GET the analysis result from https://www.virustotal.com/api/v3/analyses/{id}. If the analysis is not complete, poll up to 5 times with 3-second delays. Return: url, harmless count, malicious count, suspicious count, total engines, and an overall verdict (clean, suspicious, or malicious). Store VIRUSTOTAL_API_KEY in .env.
Paste this in Bolt.new chat
1// app/api/security/check-url/route.ts2import { NextRequest, NextResponse } from 'next/server';34const VT_BASE = 'https://www.virustotal.com/api/v3';56async function vtFetch(path: string, options: RequestInit = {}) {7 const apiKey = process.env.VIRUSTOTAL_API_KEY;8 if (!apiKey) throw new Error('VIRUSTOTAL_API_KEY not set');9 const response = await fetch(`${VT_BASE}${path}`, {10 ...options,11 headers: {12 'x-apikey': apiKey,13 ...(options.headers ?? {}),14 },15 });16 if (!response.ok) {17 throw new Error(`VirusTotal API error: ${response.status}`);18 }19 return response.json();20}2122async function waitForAnalysis(analysisId: string, maxAttempts = 5): Promise<Record<string, unknown>> {23 for (let i = 0; i < maxAttempts; i++) {24 const result = await vtFetch(`/analyses/${analysisId}`);25 if (result.data?.attributes?.status === 'completed') {26 return result;27 }28 if (i < maxAttempts - 1) {29 await new Promise((r) => setTimeout(r, 3000));30 }31 }32 throw new Error('Analysis timed out — try again in a few seconds');33}3435export async function POST(request: NextRequest) {36 const { url } = await request.json() as { url: string };3738 if (!url || !url.startsWith('http')) {39 return NextResponse.json({ error: 'Valid URL required' }, { status: 400 });40 }4142 try {43 // Step 1: Submit URL for scanning44 const urlId = btoa(url).replace(/=/g, ''); // Base64url encode without padding4546 // Try to get existing analysis first (avoids rate limit)47 let analysisData: Record<string, unknown>;48 try {49 const existing = await vtFetch(`/urls/${urlId}`);50 analysisData = existing;51 } catch {52 // URL not in cache — submit for new scan53 const submitForm = new FormData();54 submitForm.append('url', url);55 const submitted = await vtFetch('/urls', { method: 'POST', body: submitForm });56 analysisData = await waitForAnalysis(submitted.data.id);57 }5859 const stats = (analysisData.data as Record<string, unknown>)?.attributes as Record<string, Record<string, number>>;60 const lastAnalysis = stats?.last_analysis_stats ?? {};6162 const malicious = lastAnalysis.malicious ?? 0;63 const suspicious = lastAnalysis.suspicious ?? 0;64 const harmless = lastAnalysis.harmless ?? 0;65 const total = malicious + suspicious + harmless + (lastAnalysis.undetected ?? 0);6667 const verdict = malicious >= 3 ? 'malicious'68 : malicious >= 1 || suspicious >= 2 ? 'suspicious'69 : 'clean';7071 return NextResponse.json({72 url,73 verdict,74 malicious,75 suspicious,76 harmless,77 totalEngines: total,78 permalink: (analysisData.data as Record<string, unknown>)?.links as Record<string, string> ?? {},79 });80 } catch (error) {81 const message = error instanceof Error ? error.message : 'Scan failed';82 return NextResponse.json({ error: message }, { status: 500 });83 }84}Pro tip: VirusTotal caches recent URL analyses. If the URL was already scanned recently, the GET /urls/{urlId} endpoint returns the cached result instantly without consuming your rate limit quota. Always try the cached result first before submitting a new scan.
Expected result: Sending a POST to /api/security/check-url with a URL returns a verdict (clean, suspicious, or malicious), the number of antivirus engines that flagged it, and the total number of engines that scanned it.
Implement Have I Been Pwned email breach checking
Implement Have I Been Pwned email breach checking
The Have I Been Pwned (HIBP) API checks whether an email address appears in known data breaches. This is a valuable security signal at user registration — you can warn users that their email address has been found in breach databases, encouraging them to use unique passwords. HIBP requires an API key for the email breach endpoint. Keys are available at haveibeenpwned.com/API/Key for $3.50/month for personal use, or free for non-commercial usage with appropriate attribution. The endpoint is simple: GET /breachedaccount/{email} returns an array of breaches associated with that email, or 404 if no breaches are found. For password checking, HIBP provides the Pwned Passwords API which uses a k-anonymity model that protects user privacy: you hash the password with SHA-1, send only the first 5 characters of the hash to the API, and HIBP returns all hash suffixes that match those 5 characters. You then check client-side whether the full hash appears in the returned list. This means the actual password or full hash never leaves the browser. Integrate the email check into your registration flow as a non-blocking advisory. Show a warning if breaches are found but do not prevent registration — users may have already changed their passwords after a breach. For password checking, a client-side check before form submission is appropriate since the k-anonymity model means no sensitive data is transmitted. Note: both the email check and password check endpoints can be called from Bolt's WebContainer preview since they are outbound HTTP calls. The email check requires your HIBP API key in a server-side route; the password hash check uses a public endpoint that does not require authentication.
Create two security routes. First: /api/security/check-email that accepts a POST with email field, calls the HIBP v3 API at https://haveibeenpwned.com/api/v3/breachedaccount/{email} with the hibp-api-key header from HIBP_API_KEY env var, and returns the array of breach names and dates, or { breaches: [], safe: true } if the email has no known breaches. Second: /api/security/check-password that accepts the first 5 characters of a SHA-1 hash, calls https://api.pwnedpasswords.com/range/{prefix}, and returns the count of times the full hash suffix appears (or 0 if not found). Include a hash suffix parameter.
Paste this in Bolt.new chat
1// app/api/security/check-email/route.ts2import { NextRequest, NextResponse } from 'next/server';34export async function POST(request: NextRequest) {5 const { email } = await request.json() as { email: string };67 if (!email || !email.includes('@')) {8 return NextResponse.json({ error: 'Valid email required' }, { status: 400 });9 }1011 const apiKey = process.env.HIBP_API_KEY;12 if (!apiKey) {13 return NextResponse.json({ error: 'HIBP_API_KEY not configured' }, { status: 500 });14 }1516 try {17 const response = await fetch(18 `https://haveibeenpwned.com/api/v3/breachedaccount/${encodeURIComponent(email)}?truncateResponse=false`,19 {20 headers: {21 'hibp-api-key': apiKey,22 'User-Agent': 'BoltApp-SecurityCheck',23 },24 }25 );2627 if (response.status === 404) {28 return NextResponse.json({ email, breaches: [], safe: true, count: 0 });29 }3031 if (!response.ok) {32 throw new Error(`HIBP API error: ${response.status}`);33 }3435 const breaches = await response.json() as Array<{36 Name: string;37 BreachDate: string;38 PwnCount: number;39 DataClasses: string[];40 }>;4142 return NextResponse.json({43 email,44 safe: false,45 count: breaches.length,46 breaches: breaches.map((b) => ({47 name: b.Name,48 date: b.BreachDate,49 compromisedAccounts: b.PwnCount,50 dataTypes: b.DataClasses,51 })),52 });53 } catch (error) {54 const message = error instanceof Error ? error.message : 'Check failed';55 return NextResponse.json({ error: message }, { status: 500 });56 }57}5859// app/api/security/check-password/route.ts — k-anonymity password check60// Client sends only first 5 chars of SHA-1 hash61export async function GET_password(request: NextRequest) {62 const { searchParams } = new URL(request.url);63 const prefix = searchParams.get('prefix');64 const suffix = searchParams.get('suffix')?.toUpperCase();6566 if (!prefix || prefix.length !== 5 || !suffix) {67 return NextResponse.json({ error: 'prefix (5 chars) and suffix required' }, { status: 400 });68 }6970 const response = await fetch(`https://api.pwnedpasswords.com/range/${prefix}`);71 const text = await response.text();7273 const lines = text.split('\r\n');74 const match = lines.find((line) => line.startsWith(suffix));75 const count = match ? parseInt(match.split(':')[1], 10) : 0;7677 return NextResponse.json({ prefix, compromised: count > 0, occurrences: count });78}Pro tip: The Pwned Passwords API (for password hash checking) is completely free and does not require an API key. Only the email breach endpoint (/breachedaccount) requires payment. For a budget-conscious implementation, start with just the free Pwned Passwords API and add email checking later.
Expected result: Calling /api/security/check-email with a test email returns the list of data breaches that email appears in, or a { safe: true } response if the email is not found in any known breach database.
Build a security dashboard combining multiple data sources
Build a security dashboard combining multiple data sources
With VirusTotal and HIBP API routes in place, build a security monitoring dashboard that gives users visibility into security signals relevant to their Bolt app. This is useful for internal security dashboards, user account security pages, or admin panels monitoring for suspicious activity. A practical security dashboard for a Bolt app might combine: a URL scanner where admins can check URLs submitted by users, an account security section showing users whether their email appears in known breaches, and a recent scan history showing the results of previous security checks. These three features together give a clear security posture view without requiring an enterprise Trend Micro license. For the URL scanner UI, provide a text input where an admin pastes a URL, which triggers the /api/security/check-url route and displays the verdict with the engine breakdown. Show the count of malicious, suspicious, harmless, and undetected results. For HIBP, provide a field for users to check their own email — either in an account settings page or as an onboarding step. An important deployment consideration: while API calls to VirusTotal and HIBP are outbound HTTP (works in the WebContainer), a production security dashboard should be deployed and access-controlled. VirusTotal results are sensitive information — do not expose the scan results to unauthenticated users or include API keys in any code that could be visible to users.
Build a SecurityDashboard React component with two sections. Section 1 — URL Scanner: a text input for a URL, a Scan button that calls /api/security/check-url, and a results area showing a colored verdict badge (green/yellow/red), malicious count, and total engines. Show a loading spinner while scanning. Section 2 — Breach Check: an email input, a Check button that calls /api/security/check-email, and results showing either 'No known breaches' in green or a list of breach names with dates and compromised data types in red. Add a clear results button.
Paste this in Bolt.new chat
1// components/SecurityDashboard.tsx2'use client';34import { useState } from 'react';56interface UrlScanResult {7 url: string;8 verdict: 'clean' | 'suspicious' | 'malicious';9 malicious: number;10 suspicious: number;11 harmless: number;12 totalEngines: number;13}1415interface BreachResult {16 email: string;17 safe: boolean;18 count: number;19 breaches: Array<{ name: string; date: string; dataTypes: string[] }>;20}2122const verdictConfig = {23 clean: { color: 'bg-green-100 text-green-800 border-green-200', label: 'Clean' },24 suspicious: { color: 'bg-yellow-100 text-yellow-800 border-yellow-200', label: 'Suspicious' },25 malicious: { color: 'bg-red-100 text-red-800 border-red-200', label: 'Malicious' },26};2728export default function SecurityDashboard() {29 const [urlInput, setUrlInput] = useState('');30 const [urlResult, setUrlResult] = useState<UrlScanResult | null>(null);31 const [urlLoading, setUrlLoading] = useState(false);32 const [urlError, setUrlError] = useState('');3334 const [emailInput, setEmailInput] = useState('');35 const [breachResult, setBreachResult] = useState<BreachResult | null>(null);36 const [emailLoading, setEmailLoading] = useState(false);37 const [emailError, setEmailError] = useState('');3839 async function scanUrl() {40 if (!urlInput) return;41 setUrlLoading(true);42 setUrlError('');43 setUrlResult(null);44 try {45 const res = await fetch('/api/security/check-url', {46 method: 'POST',47 headers: { 'Content-Type': 'application/json' },48 body: JSON.stringify({ url: urlInput }),49 });50 const data = await res.json();51 if (data.error) throw new Error(data.error);52 setUrlResult(data);53 } catch (e) {54 setUrlError(e instanceof Error ? e.message : 'Scan failed');55 } finally {56 setUrlLoading(false);57 }58 }5960 async function checkEmail() {61 if (!emailInput) return;62 setEmailLoading(true);63 setEmailError('');64 setBreachResult(null);65 try {66 const res = await fetch('/api/security/check-email', {67 method: 'POST',68 headers: { 'Content-Type': 'application/json' },69 body: JSON.stringify({ email: emailInput }),70 });71 const data = await res.json();72 if (data.error) throw new Error(data.error);73 setBreachResult(data);74 } catch (e) {75 setEmailError(e instanceof Error ? e.message : 'Check failed');76 } finally {77 setEmailLoading(false);78 }79 }8081 return (82 <div className="p-6 max-w-2xl mx-auto space-y-8">83 <h1 className="text-2xl font-bold">Security Dashboard</h1>8485 <section className="border rounded-lg p-6">86 <h2 className="text-lg font-semibold mb-4">URL Safety Scanner</h2>87 <div className="flex gap-2 mb-4">88 <input value={urlInput} onChange={(e) => setUrlInput(e.target.value)}89 placeholder="https://example.com" className="flex-1 border rounded px-3 py-2 text-sm" />90 <button onClick={scanUrl} disabled={urlLoading}91 className="px-4 py-2 bg-blue-600 text-white rounded text-sm disabled:opacity-50">92 {urlLoading ? 'Scanning...' : 'Scan URL'}93 </button>94 </div>95 {urlError && <p className="text-red-600 text-sm">{urlError}</p>}96 {urlResult && (97 <div className={`border rounded p-4 ${verdictConfig[urlResult.verdict].color}`}>98 <div className="flex justify-between items-center mb-2">99 <span className="font-semibold">{verdictConfig[urlResult.verdict].label}</span>100 <span className="text-sm">{urlResult.malicious} / {urlResult.totalEngines} engines flagged</span>101 </div>102 <p className="text-xs truncate">{urlResult.url}</p>103 </div>104 )}105 </section>106107 <section className="border rounded-lg p-6">108 <h2 className="text-lg font-semibold mb-4">Email Breach Check</h2>109 <div className="flex gap-2 mb-4">110 <input value={emailInput} onChange={(e) => setEmailInput(e.target.value)}111 type="email" placeholder="user@example.com"112 className="flex-1 border rounded px-3 py-2 text-sm" />113 <button onClick={checkEmail} disabled={emailLoading}114 className="px-4 py-2 bg-blue-600 text-white rounded text-sm disabled:opacity-50">115 {emailLoading ? 'Checking...' : 'Check Email'}116 </button>117 </div>118 {emailError && <p className="text-red-600 text-sm">{emailError}</p>}119 {breachResult && (120 breachResult.safe ? (121 <div className="bg-green-50 border border-green-200 rounded p-4 text-green-800">122 No known data breaches found for this email address.123 </div>124 ) : (125 <div className="bg-red-50 border border-red-200 rounded p-4">126 <p className="font-semibold text-red-800 mb-2">127 Found in {breachResult.count} breach{breachResult.count !== 1 ? 'es' : ''}128 </p>129 <ul className="space-y-1">130 {breachResult.breaches.slice(0, 5).map((b) => (131 <li key={b.name} className="text-sm text-red-700">132 <strong>{b.name}</strong> ({b.date}) — {b.dataTypes.slice(0, 3).join(', ')}133 </li>134 ))}135 </ul>136 </div>137 )138 )}139 </section>140 </div>141 );142}Pro tip: Rate limit your security check endpoints on the server side. VirusTotal's free tier allows 4 requests per minute. If your app is publicly accessible, add rate limiting per IP using a simple in-memory counter or a library like rate-limiter-flexible to prevent users from exhausting your VirusTotal quota.
Expected result: The security dashboard renders in the Bolt preview with a working URL scanner and email breach checker. Scanning a known test URL (e.g., eicar.com for malware testing) returns a verdict, and checking a known compromised email returns breach details.
Common use cases
File upload malware scanning with VirusTotal
Before processing a user-uploaded file (PDF, image, document), send it to VirusTotal for analysis against 70+ antivirus engines. Block or quarantine files that receive a positive detection from multiple engines, protecting your application from malicious file uploads.
Add file upload security scanning to my Bolt app using the VirusTotal API. When a user uploads a file, send it to the VirusTotal /files endpoint for analysis, poll for the scan result, and display the detection count. If more than 2 engines flag the file as malicious, block the upload and show a warning. Store the VirusTotal API key in .env.
Copy this prompt to try it in Bolt.new
URL safety checker for user-submitted links
When users submit URLs to your app (link sharing, resource submission, external redirects), check them against VirusTotal's URL intelligence database before displaying or following them. Show a safety badge indicating whether the URL is clean, suspicious, or known malicious.
Create a URL safety check feature using the VirusTotal API. Build a UrlSafetyBadge component that accepts a URL prop, calls a /api/security/check-url route on mount, and displays a colored badge: green (clean), yellow (suspicious, 1-2 detections), or red (malicious, 3+ detections). Cache results for 24 hours to avoid repeated API calls for the same URL.
Copy this prompt to try it in Bolt.new
Compromised credential detection at user registration
When a new user registers or changes their password, check the password against the Have I Been Pwned Pwned Passwords API using the k-anonymity model (only the first 5 characters of the SHA-1 hash are sent). Warn users if their chosen password appears in breach databases.
Add compromised password detection to my signup form using the Have I Been Pwned API. When the user types a password, hash it with SHA-1 in the browser, send the first 5 hex characters to a /api/security/check-password route, which queries the HIBP Pwned Passwords API and returns the breach count. Show a warning if the password appears in any known breach. Use the k-anonymity model — never send the full password hash.
Copy this prompt to try it in Bolt.new
Troubleshooting
VirusTotal API returns 401 Unauthorized
Cause: The VIRUSTOTAL_API_KEY environment variable is missing or the API key was entered incorrectly. VirusTotal API keys are case-sensitive.
Solution: Verify the API key by logging into virustotal.com and checking your profile's API key section. Copy the key exactly and set it as VIRUSTOTAL_API_KEY in .env.local. Restart the Next.js dev server. Confirm the key is loading in your API route by logging the first 8 characters server-side.
1console.log('VT key prefix:', process.env.VIRUSTOTAL_API_KEY?.substring(0, 8));VirusTotal URL scan times out — analysis never completes
Cause: The URL was submitted for a fresh scan (not in VirusTotal's cache) and the analysis is taking longer than the polling timeout allows. Fresh scans against 70+ engines can take 60-90 seconds.
Solution: Increase the polling interval and maximum attempts in the waitForAnalysis function. For fresh URL scans, poll with 5-second intervals for up to 12 attempts (60 seconds total). Alternatively, return the analysis ID to the client and implement client-side polling that retries until the scan completes.
1// Increase timeout for fresh scans:2async function waitForAnalysis(id: string, maxAttempts = 12): Promise<Record<string, unknown>> {3 for (let i = 0; i < maxAttempts; i++) {4 const result = await vtFetch(`/analyses/${id}`);5 if (result.data?.attributes?.status === 'completed') return result;6 await new Promise((r) => setTimeout(r, 5000)); // 5 second delay7 }8 throw new Error('Analysis timeout — the scan is still running');9}HIBP API returns 429 Too Many Requests
Cause: The Have I Been Pwned API has a rate limit of 1 request per 1,500 milliseconds per API key. Multiple simultaneous requests or rapid form submissions trigger this limit.
Solution: Add a debounce to the email check UI so it only fires after the user stops typing for 500ms. Implement server-side rate limiting on your /api/security/check-email route to reject requests more frequent than once per 2 seconds per IP. Cache results for known emails so repeated checks do not consume quota.
1// Simple debounce in the React component:2import { useCallback } from 'react';3import debounce from 'lodash/debounce';4const debouncedCheck = useCallback(debounce(checkEmail, 500), []);Security API calls work in development but fail in the deployed Bolt app
Cause: Environment variables (VIRUSTOTAL_API_KEY, HIBP_API_KEY) are set in .env.local for development but not configured in the hosting platform's environment settings.
Solution: In Netlify, add the environment variables under Site Settings → Environment Variables. In Bolt Cloud, use the Secrets management panel. Trigger a redeploy after adding the variables — they are injected at runtime and the app must restart to pick them up.
Best practices
- Understand that Trend Micro's APIs require enterprise subscriptions — for practical security scanning in Bolt apps, use VirusTotal (file/URL scanning), HIBP (breach checking), or Snyk (dependency scanning) which all have accessible free tiers.
- Never scan confidential files or personally identifiable information through VirusTotal's public API — scanned content is visible to VirusTotal's community. Use VirusTotal only for checking untrusted user-submitted content.
- Always proxy security API calls through server-side Next.js routes. API keys for VirusTotal and HIBP grant usage quotas that can be exhausted — client-side exposure allows anyone to drain your quota.
- Implement rate limiting on your security check endpoints to protect your API quotas. VirusTotal's free tier (4 requests/minute) is easily exhausted if your endpoint is publicly accessible without limiting.
- Use VirusTotal's cache by checking GET /urls/{urlId} before submitting new scans. Recently scanned URLs return immediately without consuming your quota.
- Treat breach check results as advisory, not blocking. Users whose email appears in HIBP may have already changed their passwords. Show warnings that encourage password updates rather than denying account creation.
- Deploy to Netlify or Bolt Cloud before exposing security features to real users — security monitoring tools should always run in a controlled production environment, not a development preview.
Alternatives
McAfee (now Trellix) similarly targets enterprises with no accessible developer API — for Bolt developers, the same VirusTotal and HIBP alternatives apply.
Norton is a consumer and enterprise security product without a public API for developers — use VirusTotal and HIBP for the security scanning capabilities Norton provides in its consumer products.
Duo Security is a practical alternative for one specific security use case — multi-factor authentication — with a developer-accessible API and a free tier for up to 10 users.
Frequently asked questions
Can I use Trend Micro's API with Bolt.new?
Trend Micro's APIs are designed for enterprise IT teams and require paid subscriptions to products like Cloud One or Vision One. There is no self-service developer API key, no free trial, and no sandbox environment. If your organization has an active Trend Micro enterprise license, contact your account team for API documentation. For individual Bolt developers, VirusTotal, Snyk, and Have I Been Pwned are the practical alternatives.
Is VirusTotal's API free to use?
VirusTotal offers a free Public API with a limit of 4 requests per minute and 500 requests per day. This is sufficient for on-demand security checks in small to medium applications. VirusTotal Premium APIs have higher rate limits and additional features, starting at $10,000/year. For most Bolt apps, the free Public API is adequate.
Can I test VirusTotal scanning in Bolt's WebContainer preview?
Yes. VirusTotal API calls are outbound HTTP requests, which work fine in Bolt's WebContainer. You can fully test URL scanning and file hash lookups in the preview without deploying. File uploading for scanning also works since it is an outbound multipart POST request. Only incoming webhooks would require deployment, and VirusTotal does not use webhooks for its standard scanning API.
How do I scan npm packages for security vulnerabilities?
Use the Snyk API, which is purpose-built for dependency vulnerability scanning. Snyk's free tier allows 200 open-source tests per month. Call the Snyk REST API with your package name and version to get a list of known CVEs, severity scores, and remediation advice. Alternatively, the npm audit API provides vulnerability data for any npm package without requiring an API key.
Should I block user registration if an email appears in HIBP?
No. An email appearing in HIBP means the address was exposed in a past data breach, but the user may have already changed their password. The recommended pattern is to display an advisory warning and encourage the user to use a unique password that they have not used on the breached site. Blocking registration would harm user experience without meaningfully improving security, since determined users would simply use a different email.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation