Enforce CSP without unsafe-inline, and close out the remaining retest items
Some checks failed
CI / build (push) Has been cancelled

F-03: the legacy markup's 77 onclick="" attributes were the reason script-src
still needed 'unsafe-inline', which let injected inline script/handlers run
right past the policy. Migrated them to data-page/data-action markers handled
by a single delegated click listener in siteController.js, dropped
'unsafe-inline' from script-src, and switched both server/index.mjs and
vercel.json from Content-Security-Policy-Report-Only to enforcing. style-src
keeps 'unsafe-inline' — that governs inline style="" attributes used
throughout, a separate CSS-injection concern out of scope here.

Verified against the built site with a real headless-Chromium run: nav,
company dropdown, mobile menu, the demo modal (open/close/overlay-click/
inner-click), the modal's contact-page link, and the scroll-hint all still
work, with zero console errors.

F-10: confirmed via npm audit fix --dry-run that no non-breaking update
remains (vite and react-router-dom both need a major bump, left deferred).
Added npm audit to CI — full report for visibility, gated on critical only
so it doesn't block on the already-tracked moderate/high advisories.

F-11: uploaded PDFs now serve with Content-Disposition: attachment instead
of rendering inline from the site's own origin.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 21:02:53 +05:00
parent 2baac6eab4
commit 11a709744e
5 changed files with 134 additions and 91 deletions

View File

@@ -18,3 +18,9 @@ jobs:
# tsc --noEmit runs first (see package.json), so a type error fails the
# build here before anything gets deployed.
- run: npm run build
# Full report for visibility (vite/esbuild and react-router-dom currently
# carry known moderate/high advisories — both need a major-version bump,
# tracked separately rather than forced here). The build only fails on
# critical, so a genuinely new/severe advisory still blocks merges.
- run: npm audit || true
- run: npm audit --audit-level=critical

View File

@@ -162,13 +162,15 @@ setInterval(() => {
}, THROTTLE_WINDOW_MS).unref()
// ── Helpers ────────────────────────────────────────────────────────────────────
// CSP ships in report-only mode: the legacy markup relies on inline onclick=""
// handlers, so enforcing script-src today would break navigation. Report-only
// costs nothing (it can't break the site) and surfaces exactly what a real
// policy needs to allow before anyone flips it to enforcing.
// script-src has no 'unsafe-inline': the legacy markup's onclick="" attributes
// were migrated to a single delegated listener (siteController.js), and no
// inline <script> exists anywhere in the app, so there's nothing left for it to
// allow. style-src keeps 'unsafe-inline' — React's style prop and the legacy
// markup's inline style="" attributes are load-bearing throughout and out of
// scope here; that's a CSS-injection concern, not the XSS one this closes.
const CSP = [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' https://*.hubspot.com https://*.hs-scripts.com https://*.hsforms.net https://*.usemessages.com",
"script-src 'self' https://*.hubspot.com https://*.hs-scripts.com https://*.hsforms.net https://*.usemessages.com",
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
"font-src 'self' https://fonts.gstatic.com",
"img-src 'self' data: https:",
@@ -185,7 +187,7 @@ const SECURITY_HEADERS = {
'X-Frame-Options': 'SAMEORIGIN',
'Referrer-Policy': 'strict-origin-when-cross-origin',
'Permissions-Policy': 'geolocation=(), camera=(), microphone=()',
'Content-Security-Policy-Report-Only': CSP,
'Content-Security-Policy': CSP,
// Harmless (and ignored) over plain HTTP; takes effect once a browser sees it over TLS.
'Strict-Transport-Security': 'max-age=63072000; includeSubDomains',
}
@@ -268,6 +270,10 @@ async function serveFile(req, res, file, { immutable = false } = {}) {
}
const type = MIME[path.extname(file).toLowerCase()] || 'application/octet-stream'
const cache = immutable ? 'public, max-age=31536000, immutable' : 'public, max-age=300'
// Uploaded PDFs are served from the site's own origin with no sandboxing.
// Forcing a download rather than inline rendering keeps a crafted PDF from
// being used as a same-origin phishing page.
const disposition = type === 'application/pdf' ? { 'Content-Disposition': `attachment; filename="${path.basename(file)}"` } : {}
const range = /^bytes=(\d*)-(\d*)$/.exec(req.headers.range || '')
if (range) {
const start = range[1] ? Number(range[1]) : 0
@@ -278,6 +284,7 @@ async function serveFile(req, res, file, { immutable = false } = {}) {
'Accept-Ranges': 'bytes',
'Content-Length': end - start + 1,
'Cache-Control': cache,
...disposition,
...SECURITY_HEADERS,
})
fs.createReadStream(file, { start, end }).pipe(res)
@@ -288,6 +295,7 @@ async function serveFile(req, res, file, { immutable = false } = {}) {
'Content-Length': stat.size,
'Accept-Ranges': 'bytes',
'Cache-Control': cache,
...disposition,
...SECURITY_HEADERS,
})
fs.createReadStream(file).pipe(res)

View File

@@ -1,6 +1,10 @@
// BlackDice site controller — ported from the original vanilla js/main.js.
// Function declarations are exposed on window so the inline onclick handlers in the
// legacy markup (goPage(event), showDemo(), etc.) continue to resolve.
// The legacy markup no longer carries onclick="" attributes (a CSP with
// script-src 'unsafe-inline' removed would otherwise let injected inline
// script or event handlers run too) — clicks are handled by the single
// delegated listener below, keyed off data-page/data-action. Functions are
// still exposed on window because SiteApp.tsx reads window.showDemo for the
// mailto-link and "Talk to us" wiring it does independently.
/* eslint-disable */
"use strict";
@@ -472,14 +476,37 @@ function initCountUp() {
});
}
// ── Click delegation ─────────────────────────────────────────────────────────
// Replaces the onclick="" attributes the legacy markup used to carry. A single
// document-level listener means none of this depends on script-src 'unsafe-inline'.
var ACTIONS = {
"close-demo": function () { closeDemo(); },
"close-demo-p9": function () { closeDemo(); go("p9"); },
"show-demo": function () { showDemo(); },
"toggle-mob": function () { toggleMob(); },
"submit-demo": function () { submitDemo(); },
"submit-contact": function () { submitContact(); },
"scroll-down": function () { scrollDown(); },
"go-home": function () { goHome(); },
// Mirrors the original onclick="closeBg(event)" on the overlay itself: only
// fires when the click landed on the overlay, not a descendant (the modal box).
"close-bg": function (e, el) { if (e.target === el) closeDemo(); },
};
function handleSiteClick(e) {
goPage(e);
var el = e.target.closest("[data-action]");
if (!el) return;
var run = ACTIONS[el.dataset.action];
if (run) run(e, el);
}
// ── Init ───────────────────────────────────────────────────────────────────
// ── Expose globals for inline handlers ─────────────────────────────────────
// window.showDemo is the one function SiteApp.tsx still reaches for directly
// (mailto-link interception, and the "Talk to us" CTAs it wires independently).
var __w = /** @type {any} */ (window);
__w.go = go; __w.goPage = goPage; __w.goHome = goHome; __w.toggleMob = toggleMob;
__w.scrollDown = scrollDown; __w.showDemo = showDemo; __w.closeDemo = closeDemo;
__w.closeBg = closeBg; __w.submitDemo = submitDemo; __w.submitContact = submitContact;
__w.showDemo = showDemo;
var __bdFeedTimer = null;
@@ -494,6 +521,7 @@ export function initSite(startPage) {
window.addEventListener('scroll', hideHint);
}
window.addEventListener('scroll', onScroll, { passive: true });
document.addEventListener('click', handleSiteClick);
if (__bdFeedTimer) clearInterval(__bdFeedTimer);
__bdFeedTimer = setInterval(cycleFeed, 3400);
initCountUp();
@@ -501,6 +529,7 @@ export function initSite(startPage) {
export function teardownSite() {
window.removeEventListener('scroll', onScroll);
document.removeEventListener('click', handleSiteClick);
if (__bdFeedTimer) { clearInterval(__bdFeedTimer); __bdFeedTimer = null; }
document.removeEventListener('keydown', __bdModalKeydown, true);
}

View File

@@ -1,49 +1,49 @@
<!-- NAV -->
<nav id="bd-nav" class="bd-nav" style="background:rgba(1,59,73,.4);border-bottom-color:transparent">
<div style="display:flex;align-items:center;cursor:pointer;" onclick="goHome()">
<div style="display:flex;align-items:center;cursor:pointer;" data-action="go-home">
<img data-cms-img="img001" src="/logo.svg" alt="BlackDice" style="display:block;height:28px;width:auto;" />
</div>
<div class="bd-nav-links">
<button data-cms="c0001" class="bd-nl" data-nav="p1" data-page="p1" onclick="goPage(event)">Home</button>
<button data-cms="c0002" class="bd-nl" data-nav="p2" data-page="p2" onclick="goPage(event)">Mobile SDK</button>
<button data-cms="c0003" class="bd-nl" data-nav="p10" data-page="p10" onclick="goPage(event)">DNS Protect</button>
<button data-cms="c0004" class="bd-nl" data-nav="p3" data-page="p3" onclick="goPage(event)">Halo CPE</button>
<button data-cms="c0005" class="bd-nl" data-nav="p4" data-page="p4" onclick="goPage(event)">For Operators</button>
<button data-cms="c0006" class="bd-nl" data-nav="p5" data-page="p5" onclick="goPage(event)">Financial Services</button>
<button data-cms="c0001" class="bd-nl" data-nav="p1" data-page="p1">Home</button>
<button data-cms="c0002" class="bd-nl" data-nav="p2" data-page="p2">Mobile SDK</button>
<button data-cms="c0003" class="bd-nl" data-nav="p10" data-page="p10">DNS Protect</button>
<button data-cms="c0004" class="bd-nl" data-nav="p3" data-page="p3">Halo CPE</button>
<button data-cms="c0005" class="bd-nl" data-nav="p4" data-page="p4">For Operators</button>
<button data-cms="c0006" class="bd-nl" data-nav="p5" data-page="p5">Financial Services</button>
<div class="bd-drop">
<button data-cms="c0007" id="nav-co" class="bd-nl">Company ▾</button>
<div class="bd-drop-menu">
<button data-cms="c0008" class="bd-di" data-nav="p6" data-page="p6" onclick="goPage(event)">Why BlackDice?</button>
<button data-cms="c0009" class="bd-di" data-nav="p7" data-page="p7" onclick="goPage(event)">News</button>
<button data-cms="c0010" class="bd-di" data-nav="p8" data-page="p8" onclick="goPage(event)">Investors</button>
<button data-cms="c0011" class="bd-di" data-nav="p9" data-page="p9" onclick="goPage(event)">Contact</button>
<button data-cms="c0008" class="bd-di" data-nav="p6" data-page="p6">Why BlackDice?</button>
<button data-cms="c0009" class="bd-di" data-nav="p7" data-page="p7">News</button>
<button data-cms="c0010" class="bd-di" data-nav="p8" data-page="p8">Investors</button>
<button data-cms="c0011" class="bd-di" data-nav="p9" data-page="p9">Contact</button>
</div>
</div>
<button data-cms="c0012" class="bd-nl bd-nav-cta" onclick="showDemo()">Talk to us</button>
<button data-cms="c0012" class="bd-nl bd-nav-cta">Talk to us</button>
</div>
<button class="bd-ham" onclick="toggleMob()" aria-label="Menu" aria-expanded="false" aria-controls="mob-nav"><span></span><span></span><span></span></button>
<button class="bd-ham" data-action="toggle-mob" aria-label="Menu" aria-expanded="false" aria-controls="mob-nav"><span></span><span></span><span></span></button>
</nav>
<!-- MOBILE NAV -->
<div id="mob-nav" class="bd-mob" style="display:none">
<span data-cms="c0013" class="bd-mob-sl">PRODUCTS</span>
<button data-cms="c0014" data-page="p1" onclick="goPage(event)">Home</button>
<button data-cms="c0015" data-page="p2" onclick="goPage(event)">Mobile SDK</button>
<button data-cms="c0016" data-page="p10" onclick="goPage(event)">DNS Protect</button>
<button data-cms="c0017" data-page="p3" onclick="goPage(event)">Halo CPE</button>
<button data-cms="c0014" data-page="p1">Home</button>
<button data-cms="c0015" data-page="p2">Mobile SDK</button>
<button data-cms="c0016" data-page="p10">DNS Protect</button>
<button data-cms="c0017" data-page="p3">Halo CPE</button>
<span data-cms="c0018" class="bd-mob-sl">AUDIENCES</span>
<button data-cms="c0019" data-page="p4" onclick="goPage(event)">For Operators</button>
<button data-cms="c0020" data-page="p5" onclick="goPage(event)">Financial Services</button>
<button data-cms="c0019" data-page="p4">For Operators</button>
<button data-cms="c0020" data-page="p5">Financial Services</button>
<span data-cms="c0021" class="bd-mob-sl">COMPANY</span>
<button data-cms="c0022" data-page="p6" onclick="goPage(event)">Why BlackDice?</button>
<button data-cms="c0023" data-page="p7" onclick="goPage(event)">News</button>
<button data-cms="c0024" data-page="p8" onclick="goPage(event)">Investors</button>
<button data-cms="c0025" data-page="p9" onclick="goPage(event)">Contact</button>
<button data-cms="c0026" class="bd-mob-cta" onclick="showDemo()">Talk to us</button>
<button data-cms="c0022" data-page="p6">Why BlackDice?</button>
<button data-cms="c0023" data-page="p7">News</button>
<button data-cms="c0024" data-page="p8">Investors</button>
<button data-cms="c0025" data-page="p9">Contact</button>
<button data-cms="c0026" class="bd-mob-cta">Talk to us</button>
</div>
<!-- SCROLL HINT -->
<div class="scroll-hint" id="scroll-hint-btn" onclick="scrollDown()">
<div class="scroll-hint" id="scroll-hint-btn" data-action="scroll-down">
<span data-cms="c0027" class="sh-lbl">SCROLL</span>
<svg viewBox="0 0 22 14" width="22" height="14" fill="none" stroke="rgba(255,255,255,.8)" stroke-width="2.5"
stroke-linecap="round" stroke-linejoin="round">
@@ -227,8 +227,8 @@
<p data-cms="c0030" class="hero-sub">Three deployment tiers from lightweight DNS to full carrier-grade intelligence — sharing
one underlying AI engine. <strong>Start where your infrastructure is. Scale when you're ready.</strong></p>
<div class="btn-row">
<button data-cms="c0031" class="btn-p" onclick="showDemo()">Request a demonstration</button>
<button data-cms="c0032" class="btn-g" data-page="p6" onclick="goPage(event)">Explore platform</button>
<button data-cms="c0031" class="btn-p" data-action="show-demo">Request a demonstration</button>
<button data-cms="c0032" class="btn-g" data-page="p6">Explore platform</button>
</div>
</div>
<div>
@@ -291,7 +291,7 @@
banks</span><span class="tier-tagi">Mobile operators</span><span class="tier-tagi">Fintech</span>
</div>
</div>
<div class="tier-cta"><button data-cms="c0045" class="btn-p btn-sm" data-page="p2" onclick="goPage(event)">Mobile SDK
<div class="tier-cta"><button data-cms="c0045" class="btn-p btn-sm" data-page="p2">Mobile SDK
→</button></div>
</div>
<div class="tier-row">
@@ -308,7 +308,7 @@
<div data-cms="c0051" class="tier-tags"><span class="tier-tagi">ISPs</span><span class="tier-tagi">MVNOs</span><span
class="tier-tagi">Regional telcos</span></div>
</div>
<div class="tier-cta"><button data-cms="c0052" class="btn-p btn-sm" data-page="p10" onclick="goPage(event)">DNS Protect
<div class="tier-cta"><button data-cms="c0052" class="btn-p btn-sm" data-page="p10">DNS Protect
→</button></div>
</div>
<div class="tier-row">
@@ -326,7 +326,7 @@
<div data-cms="c0058" class="tier-tags"><span class="tier-tagi">Tier-1 operators</span><span class="tier-tagi">National
ISPs</span><span class="tier-tagi">CPE vendors</span></div>
</div>
<div class="tier-cta"><button data-cms="c0059" class="btn-p btn-sm" data-page="p3" onclick="goPage(event)">Halo CPE
<div class="tier-cta"><button data-cms="c0059" class="btn-p btn-sm" data-page="p3">Halo CPE
→</button></div>
</div>
</div>
@@ -521,26 +521,26 @@
<h3 data-cms="c0124">Fraud prevention that works at the session level</h3>
<p data-cms="c0125">For banks, fintechs and mobile operators who need on-device intelligence without owning network
infrastructure. Integrate in days. Reduce APP fraud liability now.</p><button data-cms="c0126" class="btn-p btn-sm"
onclick="showDemo()">Request a demonstration</button>
data-action="show-demo">Request a demonstration</button>
</div>
<div class="cta-card"><span data-cms="c0127" class="ey ax">DNS PROTECT · OPERATORS &amp; ISPs</span>
<h3 data-cms="c0128">The fastest path to a live security proposition</h3>
<p data-cms="c0129">No hardware dependency. No CPE procurement cycle. Deploy across your full subscriber base in days and
start delivering measurable security value immediately.</p><button data-cms="c0130" class="btn-p btn-sm"
onclick="showDemo()">Request a demonstration</button>
data-action="show-demo">Request a demonstration</button>
</div>
<div class="cta-card"><span data-cms="c0131" class="ey ax">HALO CPE · TIER-1 OPERATORS</span>
<h3 data-cms="c0132">Carrier-grade cyber defence at subscriber scale</h3>
<p data-cms="c0133">Full DPI, all-device IoT protection, zero-day behavioural detection. The complete platform embedded in
your existing CPE estate with no hardware changes.</p><button data-cms="c0134" class="btn-p btn-sm"
onclick="showDemo()">Request a demonstration</button>
data-action="show-demo">Request a demonstration</button>
</div>
</div>
</div>
</section>
<footer class="bd-footer"><img data-cms-img="img003" src="/logo.svg" alt="BlackDice" style="display:block;height:18px;width:auto;opacity:.75;" />
<div class="ftr-links"><button data-cms="c0135" class="ftr-link" data-page="p11" onclick="goPage(event)">Cookie
policy</button><button data-cms="c0136" class="ftr-link" data-page="p12" onclick="goPage(event)">Privacy policy</button></div>
<div class="ftr-links"><button data-cms="c0135" class="ftr-link" data-page="p11">Cookie
policy</button><button data-cms="c0136" class="ftr-link" data-page="p12">Privacy policy</button></div>
<span data-cms="c0137" class="ftr-copy">© 2026 BLACKDICE CYBER LTD.</span>
</footer>
</div>
@@ -719,7 +719,7 @@
<p data-cms="c0140" class="hero-sub">The BlackDice Mobile SDK brings behavioural intelligence directly into your app. Session
risk scoring, device integrity signals and scam detection — delivered in real time with no infrastructure
investment.</p>
<div class="btn-row"><button data-cms="c0141" class="btn-p" onclick="showDemo()">Request a demonstration</button></div>
<div class="btn-row"><button data-cms="c0141" class="btn-p" data-action="show-demo">Request a demonstration</button></div>
</div>
<div>
<div class="bd-mobile-demo-mount" id="mobile-sdk-demo-mount"></div>
@@ -914,13 +914,13 @@
<div>
<p data-cms="c0210">Most fraud prevention tools authenticate the customer. The BlackDice SDK understands the context
surrounding the customer — and that is where fraud actually begins.</p>
<div class="btn-row"><button data-cms="c0211" class="btn-p" onclick="showDemo()">Request a demonstration</button></div>
<div class="btn-row"><button data-cms="c0211" class="btn-p" data-action="show-demo">Request a demonstration</button></div>
</div>
</div>
</div>
<footer class="bd-footer"><img data-cms-img="img004" src="/logo.svg" alt="BlackDice" style="display:block;height:18px;width:auto;opacity:.75;" />
<div class="ftr-links"><button data-cms="c0212" class="ftr-link" data-page="p11" onclick="goPage(event)">Cookie
policy</button><button data-cms="c0213" class="ftr-link" data-page="p12" onclick="goPage(event)">Privacy policy</button></div>
<div class="ftr-links"><button data-cms="c0212" class="ftr-link" data-page="p11">Cookie
policy</button><button data-cms="c0213" class="ftr-link" data-page="p12">Privacy policy</button></div>
<span data-cms="c0214" class="ftr-copy">© 2026 BLACKDICE CYBER LTD.</span>
</footer>
</div>
@@ -1098,7 +1098,7 @@
<h1 data-cms="c0216" class="h1">DNS-layer protection.<br>Every subscriber.<br>Live in <em>days.</em></h1>
<p data-cms="c0217" class="hero-sub">Blocks phishing, malware and botnet domains at the point of resolution — inside your
network. No hardware dependency, no CPE procurement cycle, no client software, no subscriber action.</p>
<div class="btn-row"><button data-cms="c0218" class="btn-p" onclick="showDemo()">Request a demonstration</button></div>
<div class="btn-row"><button data-cms="c0218" class="btn-p" data-action="show-demo">Request a demonstration</button></div>
</div>
<div>
<div class="bd-feed">
@@ -1171,7 +1171,7 @@
a dead end. Operators typically launch DNS Protect across their full subscriber base in days, then extend to
BlackDice Halo on the router — adding deep packet inspection, device fingerprinting and behavioural
correlation where CPE integration allows.</p><button data-cms="c0238" class="btn-p" data-page="p3"
onclick="goPage(event)">See Halo CPE →</button>
>See Halo CPE →</button>
</div>
</div>
</section>
@@ -1200,13 +1200,13 @@
<div>
<p data-cms="c0249">DNS Protect delivers measurable security value without touching a single router. When you are ready for
behavioural intelligence at the edge, the intelligence layer is already in place.</p>
<div class="btn-row"><button data-cms="c0250" class="btn-p" onclick="showDemo()">Request a demonstration</button></div>
<div class="btn-row"><button data-cms="c0250" class="btn-p" data-action="show-demo">Request a demonstration</button></div>
</div>
</div>
</div>
<footer class="bd-footer"><img data-cms-img="img005" src="/logo.svg" alt="BlackDice" style="display:block;height:18px;width:auto;opacity:.75;" />
<div class="ftr-links"><button data-cms="c0251" class="ftr-link" data-page="p11" onclick="goPage(event)">Cookie
policy</button><button data-cms="c0252" class="ftr-link" data-page="p12" onclick="goPage(event)">Privacy policy</button></div>
<div class="ftr-links"><button data-cms="c0251" class="ftr-link" data-page="p11">Cookie
policy</button><button data-cms="c0252" class="ftr-link" data-page="p12">Privacy policy</button></div>
<span data-cms="c0253" class="ftr-copy">© 2026 BLACKDICE CYBER LTD.</span>
</footer>
</div>
@@ -1385,7 +1385,7 @@
<p data-cms="c0256" class="hero-sub">BlackDice Halo embeds directly into your existing CPE estate via firmware, TR-069/369 or
containerised deployment. Full DPI, all-device IoT protection and zero-day behavioural detection at
subscriber scale — with no latency impact and no user friction.</p>
<div class="btn-row"><button data-cms="c0257" class="btn-p" onclick="showDemo()">Request a demonstration</button></div>
<div class="btn-row"><button data-cms="c0257" class="btn-p" data-action="show-demo">Request a demonstration</button></div>
</div>
<div>
<div class="metrics-grid">
@@ -1648,13 +1648,13 @@
<div>
<p data-cms="c0346">Every router in your estate has the potential to be an intelligent security edge — generating new revenue,
reducing support costs and protecting your subscriber base from threats that DNS-only tools cannot see.</p>
<div class="btn-row"><button data-cms="c0347" class="btn-p" onclick="showDemo()">Request a demonstration</button></div>
<div class="btn-row"><button data-cms="c0347" class="btn-p" data-action="show-demo">Request a demonstration</button></div>
</div>
</div>
</div>
<footer class="bd-footer"><img data-cms-img="img008" src="/logo.svg" alt="BlackDice" style="display:block;height:18px;width:auto;opacity:.75;" />
<div class="ftr-links"><button data-cms="c0348" class="ftr-link" data-page="p11" onclick="goPage(event)">Cookie
policy</button><button data-cms="c0349" class="ftr-link" data-page="p12" onclick="goPage(event)">Privacy policy</button></div>
<div class="ftr-links"><button data-cms="c0348" class="ftr-link" data-page="p11">Cookie
policy</button><button data-cms="c0349" class="ftr-link" data-page="p12">Privacy policy</button></div>
<span data-cms="c0350" class="ftr-copy">© 2026 BLACKDICE CYBER LTD.</span>
</footer>
</div>
@@ -1834,7 +1834,7 @@
years will be those who can deliver something more valuable: a trusted digital environment for every
subscriber. BlackDice makes that possible — embedded in your existing infrastructure, at network scale, with
no hardware changes.</p>
<div class="btn-row"><button data-cms="c0354" class="btn-p" onclick="showDemo()">Request a demonstration</button></div>
<div class="btn-row"><button data-cms="c0354" class="btn-p" data-action="show-demo">Request a demonstration</button></div>
</div>
<div>
<div class="bd-feed">
@@ -2062,13 +2062,13 @@
<p data-cms="c0411">Talk to BlackDice to understand how the three outcomes — confidence while connected, security of
experience, and security of economics — translate to your network, your subscriber base, and your commercial
roadmap.</p>
<div class="btn-row"><button data-cms="c0412" class="btn-p" onclick="showDemo()">Request a demonstration</button></div>
<div class="btn-row"><button data-cms="c0412" class="btn-p" data-action="show-demo">Request a demonstration</button></div>
</div>
</div>
</div>
<footer class="bd-footer"><img data-cms-img="img009" src="/logo.svg" alt="BlackDice" style="display:block;height:18px;width:auto;opacity:.75;" />
<div class="ftr-links"><button data-cms="c0413" class="ftr-link" data-page="p11" onclick="goPage(event)">Cookie
policy</button><button data-cms="c0414" class="ftr-link" data-page="p12" onclick="goPage(event)">Privacy policy</button></div>
<div class="ftr-links"><button data-cms="c0413" class="ftr-link" data-page="p11">Cookie
policy</button><button data-cms="c0414" class="ftr-link" data-page="p12">Privacy policy</button></div>
<span data-cms="c0415" class="ftr-copy">© 2026 BLACKDICE CYBER LTD.</span>
</footer>
</div>
@@ -2248,7 +2248,7 @@
understands the context surrounding the customer — and that is where fraud actually begins. Real-time
behavioural intelligence, session risk scoring and scam detection, embedded directly into your existing
application.</p>
<div class="btn-row"><button data-cms="c0419" class="btn-p" onclick="showDemo()">Request a demonstration</button></div>
<div class="btn-row"><button data-cms="c0419" class="btn-p" data-action="show-demo">Request a demonstration</button></div>
</div>
<div>
<div class="bd-feed">
@@ -2373,13 +2373,13 @@
<p data-cms="c0456">Most fraud prevention tools authenticate the customer. The BlackDice SDK understands the context
surrounding the customer — and that is where fraud actually begins. Talk to our financial services team to
understand how the SDK maps to your specific risk environment.</p>
<div class="btn-row"><button data-cms="c0457" class="btn-p" onclick="showDemo()">Request a demonstration</button></div>
<div class="btn-row"><button data-cms="c0457" class="btn-p" data-action="show-demo">Request a demonstration</button></div>
</div>
</div>
</div>
<footer class="bd-footer"><img data-cms-img="img010" src="/logo.svg" alt="BlackDice" style="display:block;height:18px;width:auto;opacity:.75;" />
<div class="ftr-links"><button data-cms="c0458" class="ftr-link" data-page="p11" onclick="goPage(event)">Cookie
policy</button><button data-cms="c0459" class="ftr-link" data-page="p12" onclick="goPage(event)">Privacy policy</button></div>
<div class="ftr-links"><button data-cms="c0458" class="ftr-link" data-page="p11">Cookie
policy</button><button data-cms="c0459" class="ftr-link" data-page="p12">Privacy policy</button></div>
<span data-cms="c0460" class="ftr-copy">© 2026 BLACKDICE CYBER LTD.</span>
</footer>
</div>
@@ -2558,7 +2558,7 @@
<p data-cms="c0463" class="hero-sub">We believe everyone deserves a safe, trusted digital environment. BlackDice was built to
make that a reality — embedded in the networks people already rely on, protecting them automatically, at
scale.</p>
<div class="btn-row"><button data-cms="c0464" class="btn-p" onclick="showDemo()">Request a demonstration</button></div>
<div class="btn-row"><button data-cms="c0464" class="btn-p" data-action="show-demo">Request a demonstration</button></div>
</div>
<div>
<div class="metrics-grid">
@@ -2659,13 +2659,13 @@
<div>
<p data-cms="c0497">Talk to our team about how BlackDice deploys within your infrastructure to protect your subscribers from
day one — at operator scale, without hardware changes.</p>
<div class="btn-row"><button data-cms="c0498" class="btn-p" onclick="showDemo()">Request a demonstration</button></div>
<div class="btn-row"><button data-cms="c0498" class="btn-p" data-action="show-demo">Request a demonstration</button></div>
</div>
</div>
</div>
<footer class="bd-footer"><img data-cms-img="img011" src="/logo.svg" alt="BlackDice" style="display:block;height:18px;width:auto;opacity:.75;" />
<div class="ftr-links"><button data-cms="c0499" class="ftr-link" data-page="p11" onclick="goPage(event)">Cookie
policy</button><button data-cms="c0500" class="ftr-link" data-page="p12" onclick="goPage(event)">Privacy policy</button></div>
<div class="ftr-links"><button data-cms="c0499" class="ftr-link" data-page="p11">Cookie
policy</button><button data-cms="c0500" class="ftr-link" data-page="p12">Privacy policy</button></div>
<span data-cms="c0501" class="ftr-copy">© 2026 BLACKDICE CYBER LTD.</span>
</footer>
</div>
@@ -2851,8 +2851,8 @@
</div>
</section>
<footer class="bd-footer"><img data-cms-img="img012" src="/logo.svg" alt="BlackDice" style="display:block;height:18px;width:auto;opacity:.75;" />
<div class="ftr-links"><button data-cms="c0528" class="ftr-link" data-page="p11" onclick="goPage(event)">Cookie
policy</button><button data-cms="c0529" class="ftr-link" data-page="p12" onclick="goPage(event)">Privacy policy</button></div>
<div class="ftr-links"><button data-cms="c0528" class="ftr-link" data-page="p11">Cookie
policy</button><button data-cms="c0529" class="ftr-link" data-page="p12">Privacy policy</button></div>
<span data-cms="c0530" class="ftr-copy">© 2026 BLACKDICE CYBER LTD.</span>
</footer>
</div>
@@ -3045,7 +3045,7 @@
<p data-cms="c0535" style="font-size:15px;color:var(--t2);line-height:1.8;margin-bottom:16px;">BlackDice is granted-patent
protected across three jurisdictions (EP3231153B1, GB2533101, AU2015359182) with a unique
embedded-in-infrastructure data position that cannot be replicated by over-the-top applications or adapted
enterprise tools.</p><button data-cms="c0536" class="btn-p" onclick="showDemo()">Investor enquiries</button>
enterprise tools.</p><button data-cms="c0536" class="btn-p" data-action="show-demo">Investor enquiries</button>
</div>
</div>
<div class="g2">
@@ -3073,8 +3073,8 @@
</div>
</section>
<footer class="bd-footer"><img data-cms-img="img013" src="/logo.svg" alt="BlackDice" style="display:block;height:18px;width:auto;opacity:.75;" />
<div class="ftr-links"><button data-cms="c0549" class="ftr-link" data-page="p11" onclick="goPage(event)">Cookie
policy</button><button data-cms="c0550" class="ftr-link" data-page="p12" onclick="goPage(event)">Privacy policy</button></div>
<div class="ftr-links"><button data-cms="c0549" class="ftr-link" data-page="p11">Cookie
policy</button><button data-cms="c0550" class="ftr-link" data-page="p12">Privacy policy</button></div>
<span data-cms="c0551" class="ftr-copy">© 2026 BLACKDICE CYBER LTD.</span>
</footer>
</div>
@@ -3267,7 +3267,7 @@
<p data-cms="c0559" style="color:rgba(232,244,243,.6);font-size:14px;line-height:1.7;margin-bottom:20px;">See BlackDice Halo
in action. Our team will walk you through a live demonstration tailored to your infrastructure and
subscriber base.</p>
<button data-cms="c0560" class="btn-p btn-sm" onclick="showDemo()">Book a demonstration</button>
<button data-cms="c0560" class="btn-p btn-sm" data-action="show-demo">Book a demonstration</button>
</div>
<div style="background:#ffffff;border:1px solid #E2E0DC;padding:24px;margin-bottom:16px;">
<span data-cms="c0561" class="ey ax" style="margin-bottom:10px;">GENERAL ENQUIRIES</span>
@@ -3318,7 +3318,7 @@
team.</p>
<button data-cms="c0579"
style="font-size:14px;font-weight:600;color:var(--ax);padding:0;background:none;border:none;cursor:pointer;font-family:var(--ff);"
data-page="p7" onclick="goPage(event)">View our newsroom →</button>
data-page="p7">View our newsroom →</button>
</div>
</div>
</div>
@@ -3545,7 +3545,7 @@
placeholder="Briefly describe your network environment and the challenge you're looking to address..."
style="resize:vertical;height:80px;"></textarea></div>
<p data-cms="c0647" class="form-err" id="contact-err" style="display:none">Please add your name and work email before sending.</p>
<button data-cms="c0596" class="btn-p" style="width:100%;" onclick="submitContact()">Send enquiry</button>
<button data-cms="c0596" class="btn-p" style="width:100%;" data-action="submit-contact">Send enquiry</button>
</div>
<div id="contact-sent" class="form-sent" style="display:none">
<h3 data-cms="c0648">Enquiry sent.</h3>
@@ -3755,8 +3755,8 @@
</div>
</section>
<footer class="bd-footer"><img data-cms-img="img014" src="/logo.svg" alt="BlackDice" style="display:block;height:18px;width:auto;opacity:.75;" />
<div class="ftr-links"><button data-cms="c0610" class="ftr-link" data-page="p11" onclick="goPage(event)">Cookie
policy</button><button data-cms="c0611" class="ftr-link" data-page="p12" onclick="goPage(event)">Privacy policy</button>
<div class="ftr-links"><button data-cms="c0610" class="ftr-link" data-page="p11">Cookie
policy</button><button data-cms="c0611" class="ftr-link" data-page="p12">Privacy policy</button>
</div><span data-cms="c0612" class="ftr-copy">© 2026 BLACKDICE CYBER LTD.</span>
</footer>
</div>
@@ -3960,16 +3960,16 @@
</div>
</section>
<footer class="bd-footer"><img data-cms-img="img015" src="/logo.svg" alt="BlackDice" style="display:block;height:18px;width:auto;opacity:.75;" />
<div class="ftr-links"><button data-cms="c0627" class="ftr-link" data-page="p11" onclick="goPage(event)">Cookie
policy</button><button data-cms="c0628" class="ftr-link" data-page="p12" onclick="goPage(event)">Privacy policy</button>
<div class="ftr-links"><button data-cms="c0627" class="ftr-link" data-page="p11">Cookie
policy</button><button data-cms="c0628" class="ftr-link" data-page="p12">Privacy policy</button>
</div><span data-cms="c0629" class="ftr-copy">© 2026 BLACKDICE CYBER LTD.</span>
</footer>
</div>
<!-- ═══ DEMO MODAL ═══ -->
<div id="modal-ov" class="modal-ov" style="display:none" onclick="closeBg(event)">
<div id="modal-ov" class="modal-ov" style="display:none" data-action="close-bg">
<div class="modal-box" role="dialog" aria-modal="true" aria-label="Request a demonstration">
<button data-cms="c0630" class="modal-x" onclick="closeDemo()">✕</button>
<button data-cms="c0630" class="modal-x" data-action="close-demo">✕</button>
<div id="modal-form" style="display:block">
<span data-cms="c0631"
style="font-family:var(--fm);font-size:11px;letter-spacing:.2em;color:var(--ax);display:block;margin-bottom:12px;">REQUEST
@@ -4000,10 +4000,10 @@
fields before sending.</p>
<button data-cms="c0640"
style="width:100%;height:44px;background:var(--ax);color:#0D1B24;font-family:var(--ff);font-weight:700;font-size:14px;border:none;cursor:pointer;letter-spacing:.02em;"
onclick="submitDemo()">Send request →</button>
data-action="submit-demo">Send request →</button>
<p style="text-align:center;margin-top:16px;font-size:13px;color:#5E6C75;">or <button data-cms="c0641"
style="background:none;border:none;color:var(--ax);font-family:var(--ff);font-size:13px;font-weight:700;cursor:pointer;padding:0;text-decoration:underline;"
onclick="closeDemo();go('p9')">visit our contact page →</button></p>
data-action="close-demo-p9">visit our contact page →</button></p>
</div>
<div id="modal-sent" style="display:none;text-align:center;padding:24px 0;">
<div data-cms="c0642" style="font-size:40px;margin-bottom:16px;">✓</div>
@@ -4013,7 +4013,7 @@
shortly.</p>
<button data-cms="c0645"
style="margin-top:18px;height:44px;padding:0 24px;background:var(--ax);color:#0D1B24;font-family:var(--ff);font-weight:700;font-size:14px;border:none;cursor:pointer;"
onclick="closeDemo()">Close</button>
data-action="close-demo">Close</button>
</div>
</div>
</div>

View File

@@ -11,7 +11,7 @@
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
{ "key": "Permissions-Policy", "value": "geolocation=(), camera=(), microphone=()" },
{ "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains" },
{ "key": "Content-Security-Policy-Report-Only", "value": "default-src 'self'; script-src 'self' 'unsafe-inline' https://*.hubspot.com https://*.hs-scripts.com https://*.hsforms.net https://*.usemessages.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; media-src 'self'; connect-src 'self' https://*.hubspot.com https://*.hsforms.com https://*.hs-analytics.net; frame-src https://*.hubspot.com https://*.hsforms.com; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" }
{ "key": "Content-Security-Policy", "value": "default-src 'self'; script-src 'self' https://*.hubspot.com https://*.hs-scripts.com https://*.hsforms.net https://*.usemessages.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; media-src 'self'; connect-src 'self' https://*.hubspot.com https://*.hsforms.com https://*.hs-analytics.net; frame-src https://*.hubspot.com https://*.hsforms.com; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" }
]
}
]