MEDIUM 6.1 npm

Froala WYSIWYG editor allows cross-site scripting (XSS)

GHSA-549p-5c7f-c5p4 · CVE-2024-51434

Published · Modified

AI SAST

Find this class of vulnerability in your own code

Corgea's AI-native static analysis detects vulnerabilities like this one across your repositories, ranks them by exploitability, and returns review-ready fixes.

Description

Inconsistent

tag parsing allows for XSS in Froala WYSIWYG editor 4.3.0 and earlier.</p> </div> </div> <div class="detail-block" data-astro-cid-yq6tzhwm> <h2 data-astro-cid-yq6tzhwm>References</h2> <ul class="references-list" data-astro-cid-yq6tzhwm> <li data-astro-cid-yq6tzhwm> <span class="ref-type" data-astro-cid-yq6tzhwm>ADVISORY</span> <a href="https://nvd.nist.gov/vuln/detail/CVE-2024-51434" target="_blank" rel="noopener noreferrer" data-astro-cid-yq6tzhwm>https://nvd.nist.gov/vuln/detail/CVE-2024-51434</a> </li><li data-astro-cid-yq6tzhwm> <span class="ref-type" data-astro-cid-yq6tzhwm>WEB</span> <a href="https://georgyg.com/home/froala-wysiwyg-editor---xss-cve-2024-51434" target="_blank" rel="noopener noreferrer" data-astro-cid-yq6tzhwm>https://georgyg.com/home/froala-wysiwyg-editor---xss-cve-2024-51434</a> </li><li data-astro-cid-yq6tzhwm> <span class="ref-type" data-astro-cid-yq6tzhwm>PACKAGE</span> <a href="https://github.com/froala/wysiwyg-editor" target="_blank" rel="noopener noreferrer" data-astro-cid-yq6tzhwm>https://github.com/froala/wysiwyg-editor</a> </li> </ul> </div> <section class="related-advisories" data-astro-cid-o72stzoy> <h2 class="related-heading" data-astro-cid-o72stzoy>More npm vulnerabilities</h2> <ul class="related-list" data-astro-cid-o72stzoy> <li class="related-item" data-astro-cid-o72stzoy> <a class="related-link" href="/advisories/vulnerabilities/CVE-2026-33060" data-astro-cid-o72stzoy> <span class="related-meta" data-astro-cid-o72stzoy> <span class="severity-badge severity-medium" data-astro-cid-4za4zoa6> MEDIUM 5.7 </span> <span class="related-id" data-astro-cid-o72stzoy>CVE-2026-33060</span> <time class="related-date" datetime="2026-03-18T12:59:42Z" data-astro-cid-o72stzoy>Mar 18, 2026</time> </span> <span class="related-summary" data-astro-cid-o72stzoy>SSRF in @aborruso/ckan-mcp-server via base_url allows access to internal networks</span> </a> </li><li class="related-item" data-astro-cid-o72stzoy> <a class="related-link" href="/advisories/vulnerabilities/CVE-2026-53509" data-astro-cid-o72stzoy> <span class="related-meta" data-astro-cid-o72stzoy> <span class="severity-badge severity-medium" data-astro-cid-4za4zoa6> MEDIUM 5.7 </span> <span class="related-id" data-astro-cid-o72stzoy>CVE-2026-53509</span> <time class="related-date" datetime="2026-07-07T19:35:57Z" data-astro-cid-o72stzoy>Jul 7, 2026</time> </span> <span class="related-summary" data-astro-cid-o72stzoy>@aborruso/ckan-mcp-server: SSRF via base_url allows access to internal networks (Potential fix bypass of CVE-2026-33060)</span> </a> </li><li class="related-item" data-astro-cid-o72stzoy> <a class="related-link" href="/advisories/vulnerabilities/CVE-2026-61612" data-astro-cid-o72stzoy> <span class="related-meta" data-astro-cid-o72stzoy> <span class="severity-badge severity-medium" data-astro-cid-4za4zoa6> MEDIUM 5.7 </span> <span class="related-id" data-astro-cid-o72stzoy>CVE-2026-61612</span> <time class="related-date" datetime="2026-09-22T14:51:20Z" data-astro-cid-o72stzoy>Sep 22, 2026</time> </span> <span class="related-summary" data-astro-cid-o72stzoy>@aborruso/ckan-mcp-server has SSRF via DNS-name → internal IP — incomplete fix of CVE-2026-53509</span> </a> </li><li class="related-item" data-astro-cid-o72stzoy> <a class="related-link" href="/advisories/vulnerabilities/CVE-2026-63628" data-astro-cid-o72stzoy> <span class="related-meta" data-astro-cid-o72stzoy> <span class="related-id" data-astro-cid-o72stzoy>CVE-2026-63628</span> <time class="related-date" datetime="2026-09-22T20:34:19Z" data-astro-cid-o72stzoy>Sep 22, 2026</time> </span> <span class="related-summary" data-astro-cid-o72stzoy>mppx: Gas Draining with access list</span> </a> </li><li class="related-item" data-astro-cid-o72stzoy> <a class="related-link" href="/advisories/vulnerabilities/CVE-2026-76909" data-astro-cid-o72stzoy> <span class="related-meta" data-astro-cid-o72stzoy> <span class="related-id" data-astro-cid-o72stzoy>CVE-2026-76909</span> <time class="related-date" datetime="2026-09-22T20:34:38Z" data-astro-cid-o72stzoy>Sep 22, 2026</time> </span> <span class="related-summary" data-astro-cid-o72stzoy>Unleash: CR-approval email renders user-controlled raw HTML</span> </a> </li> </ul> <div class="related-index-wrap" data-astro-cid-o72stzoy> <nav class="ecosystem-index-links" aria-label="Browse related advisories" data-astro-cid-exv7fzmn> <a class="ecosystem-index-link" href="/advisories/vulnerabilities?ecosystem=npm" data-astro-cid-exv7fzmn>npm vulnerabilities &rarr;</a><a class="ecosystem-index-link" href="/advisories/malware?ecosystem=npm" data-astro-cid-exv7fzmn>npm malicious packages &rarr;</a><a class="ecosystem-index-link" href="/advisories/packages?ecosystem=npm" data-astro-cid-exv7fzmn>npm packages &rarr;</a> <a class="ecosystem-index-link" href="/advisories" data-astro-cid-exv7fzmn>All Corgea advisories &rarr;</a> </nav> </div> </section> </div> <aside class="detail-sidebar" data-astro-cid-yq6tzhwm> <div class="card sidebar-card score-card" data-astro-cid-yq6tzhwm> <div class="score-ring-wrap" data-astro-cid-yq6tzhwm> <svg class="score-ring" viewBox="0 0 120 120" width="120" height="120" data-astro-cid-yq6tzhwm> <circle cx="60" cy="60" r="52" fill="none" stroke="var(--line)" stroke-width="8" data-astro-cid-yq6tzhwm></circle> <circle cx="60" cy="60" r="52" fill="none" stroke="#ffb347" stroke-width="8" stroke-linecap="round" stroke-dasharray="199.47 327" transform="rotate(-90 60 60)" data-astro-cid-yq6tzhwm></circle> </svg> <div class="score-ring-inner" data-astro-cid-yq6tzhwm> <span class="score-number" style="color: #ffb347" data-astro-cid-yq6tzhwm> 6.1 </span> <span class="score-label" data-astro-cid-yq6tzhwm>/ 10</span> </div> </div> <span class="score-severity-badge" style="background: rgba(255,179,71,0.12); color: #ffb347" data-astro-cid-yq6tzhwm> MEDIUM </span> <code class="cvss-vector" data-astro-cid-yq6tzhwm>CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N</code> </div> <div class="card sidebar-card affected-packages-card" data-astro-cid-yq6tzhwm> <h3 data-astro-cid-yq6tzhwm>Affected Packages</h3> <div class="affected-pkg" data-astro-cid-yq6tzhwm> <a class="pkg-name" href="/advisories/packages/packagist/froala/wysiwyg-editor" data-astro-cid-yq6tzhwm> Packagist/froala/wysiwyg-editor </a> <div class="introduced-version" data-astro-cid-yq6tzhwm> <span class="intro-label" data-astro-cid-yq6tzhwm>Introduced</span> <span class="intro-value" data-astro-cid-yq6tzhwm>0</span> </div> <details class="versions-details" data-astro-cid-yq6tzhwm> <summary data-astro-cid-yq6tzhwm>88 affected versions</summary> <div class="version-list" data-astro-cid-yq6tzhwm> <span class="chip version-chip" data-astro-cid-yq6tzhwm>2.7.1</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>4.3.0</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.3.5</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.4.0</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.4.0-rc.1</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.4.1</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.4.2</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.5.0</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.5.1</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.6.0</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.6.1</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.6.2</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.6.3</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.6.4</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.6.5</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.6.6</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.7.0</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.7.2</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.7.3</span><span class="chip version-chip" data-astro-cid-yq6tzhwm>v2.7.4</span> <span class="chip version-chip" data-astro-cid-yq6tzhwm>+68 more</span> </div> </details> </div><div class="affected-pkg" data-astro-cid-yq6tzhwm> <a class="pkg-name" href="/advisories/packages/npm/froala-editor" data-astro-cid-yq6tzhwm> npm/froala-editor </a> <div class="introduced-version" data-astro-cid-yq6tzhwm> <span class="intro-label" data-astro-cid-yq6tzhwm>Introduced</span> <span class="intro-value" data-astro-cid-yq6tzhwm>0</span> </div> <details class="versions-details" data-astro-cid-yq6tzhwm> <summary data-astro-cid-yq6tzhwm>1 affected version</summary> <div class="version-list" data-astro-cid-yq6tzhwm> <span class="chip version-chip" data-astro-cid-yq6tzhwm>4.3.0</span> </div> </details> </div> </div> <div class="card sidebar-card" data-astro-cid-yq6tzhwm> <h3 data-astro-cid-yq6tzhwm>Scan for this vulnerability</h3> <p data-astro-cid-yq6tzhwm>Find out if your repositories are affected by CVE-2024-51434.</p> <a class="button button-primary" href="https://corgea.app" data-astro-cid-yq6tzhwm>Scan with Corgea</a> <a class="button button-ghost" href="/contact" data-astro-cid-yq6tzhwm>Book a demo</a> </div> <div class="card learn-sast-card learn-sast-card--sidebar" data-astro-cid-l7pjr2hi> <span class="learn-sast-eyebrow" data-astro-cid-l7pjr2hi>Learn</span> <a class="learn-sast-title" href="/learn/what-is-sast" data-astro-cid-l7pjr2hi>What is SAST?</a> <p class="learn-sast-text" data-astro-cid-l7pjr2hi> Static Application Security Testing finds vulnerabilities like this one in source code before it ships. <a class="learn-sast-more" href="/learn/what-is-sast" data-astro-cid-l7pjr2hi>Read the guide &rarr;</a> </p> </div> <div class="card sidebar-card" data-astro-cid-yq6tzhwm> <h3 data-astro-cid-yq6tzhwm>Aliases</h3> <div class="alias-list" data-astro-cid-yq6tzhwm> <span class="chip" data-astro-cid-yq6tzhwm>CVE-2024-51434</span> </div> </div> </aside> </div> </section> <section class="section cta-section" aria-labelledby="compact-cta-title" data-astro-cid-4kghit35> <div class="container" data-astro-cid-4kghit35> <div class="card cta-shell" data-astro-cid-4kghit35> <div class="cta-copy" data-astro-cid-4kghit35> <p class="cta-label" data-astro-cid-4kghit35>Ready to move</p> <h2 id="compact-cta-title" data-astro-cid-4kghit35>Start Securing</h2> </div> <div class="cta-actions" data-astro-cid-4kghit35> <a class="button button-primary" href="https://www.corgea.app/registration/?utm_source=corgea.com&amp;utm_medium=cta&amp;utm_campaign=advisories-vulnerabilities-cve-2024-51434&amp;utm_content=compact-cta&amp;ref=advisories-vulnerabilities-cve-2024-51434%3Acompact-cta&amp;source=advisories-vulnerabilities-cve-2024-51434" data-posthog-cta data-posthog-cta-type="signup" data-posthog-placement="compact-cta" data-posthog-label="Start for Free" data-posthog-campaign="advisories-vulnerabilities-cve-2024-51434"> Start for Free </a> <a class="button button-ghost" href="/demo?utm_source=corgea.com&amp;utm_medium=cta&amp;utm_campaign=advisories-vulnerabilities-cve-2024-51434&amp;utm_content=compact-cta&amp;ref=advisories-vulnerabilities-cve-2024-51434%3Acompact-cta&amp;source=advisories-vulnerabilities-cve-2024-51434" data-posthog-cta data-posthog-cta-type="demo" data-posthog-placement="compact-cta" data-posthog-label="Get Demo" data-posthog-campaign="advisories-vulnerabilities-cve-2024-51434"> Get Demo </a> </div> <p class="cta-assurance" data-astro-cid-4kghit35>Free, no credit card | First findings in minutes</p> </div> </div> </section> </main> <footer class="site-footer section" data-astro-cid-gcn2mc3v> <div class="container wrap card" data-astro-cid-gcn2mc3v> <div class="brand-column" data-astro-cid-gcn2mc3v> <p class="brand" data-astro-cid-gcn2mc3v>Corgea</p> <p data-astro-cid-gcn2mc3v>Application security that actually fixes the work, not just reports it.</p> <div class="social-row" aria-label="Social links" data-astro-cid-gcn2mc3v> <a href="https://www.linkedin.com/company/corgea/" target="_blank" rel="noopener noreferrer" data-astro-cid-gcn2mc3v> LinkedIn </a> <a href="https://x.com/corgeainc" target="_blank" rel="noopener noreferrer" data-astro-cid-gcn2mc3v> X </a> </div> <div class="trust-row" aria-label="Trust and compliance badges" data-astro-cid-gcn2mc3v> <div class="trust-item trust-item--yc" data-astro-cid-gcn2mc3v> <span class="trust-label" data-astro-cid-gcn2mc3v>Backed by</span> <img src="/badges/y-combinator.png" alt="Y Combinator" width="1200" height="342" loading="lazy" decoding="async" data-astro-cid-gcn2mc3v> </div> <a class="trust-item trust-item--soc" href="https://www.aicpa.org/soc4so" target="_blank" rel="noopener noreferrer" aria-label="SOC 2 Type II compliant" data-astro-cid-gcn2mc3v> <img src="/badges/aicpa-soc2-type-ii.png" alt="AICPA SOC for Service Organizations SOC 2 Type II" width="1463" height="1463" loading="lazy" decoding="async" data-astro-cid-gcn2mc3v> </a> </div> </div> <div data-astro-cid-gcn2mc3v> <p class="label" data-astro-cid-gcn2mc3v>Products</p> <a href="/products/ai-sast" data-astro-cid-gcn2mc3v>AI SAST</a><a href="/products/dependency-scanning" data-astro-cid-gcn2mc3v>Dependency Scanning</a><a href="/products/iac-scanning" data-astro-cid-gcn2mc3v>IaC Scanning</a><a href="/products/container-scanning" data-astro-cid-gcn2mc3v>Container Scanning</a><a href="/products/code-quality-scanning" data-astro-cid-gcn2mc3v>Code Quality Scanning</a><a href="/products/secrets-scanning" data-astro-cid-gcn2mc3v>Secrets Scanning</a><a href="/products/sboms-license-enforcement" data-astro-cid-gcn2mc3v>SBOMs &amp; License Enforcement</a><a href="/products/developer-experience" data-astro-cid-gcn2mc3v>Developer Experience</a><a href="/products/attack-surface-mapping" data-astro-cid-gcn2mc3v>Attack Surface Mapping</a><a href="/products/skills-scanning-registry" data-astro-cid-gcn2mc3v>Skills Scanning &amp; Registry</a><a href="/products/ai-pentest" data-astro-cid-gcn2mc3v>AI Pentest</a><a href="/products/security-design-review" data-astro-cid-gcn2mc3v>Security Design Review</a> </div> <div data-astro-cid-gcn2mc3v> <p class="label" data-astro-cid-gcn2mc3v>Solutions</p> <a href="/solutions/cisos" data-astro-cid-gcn2mc3v>CISOs</a><a href="/solutions/security-engineers" data-astro-cid-gcn2mc3v>Security Engineers</a><a href="/solutions/developers" data-astro-cid-gcn2mc3v>Developers</a><a href="/solutions/devops" data-astro-cid-gcn2mc3v>DevOps</a><a href="/solutions/agents" data-astro-cid-gcn2mc3v>Agents</a><a href="/solutions/fintech-financial-services" data-astro-cid-gcn2mc3v>Fintech &amp; Financial Services</a><a href="/solutions/enterprise-saas" data-astro-cid-gcn2mc3v>Enterprise SaaS</a><a href="/solutions/healthcare-biotech" data-astro-cid-gcn2mc3v>Healthcare &amp; Biotech</a><a href="/solutions/energy" data-astro-cid-gcn2mc3v>Energy</a><a href="/solutions/startups" data-astro-cid-gcn2mc3v>Startups</a><a href="/solutions/consumer-retail" data-astro-cid-gcn2mc3v>Consumer &amp; Retail</a><a href="/solutions/hardware-manufacturing" data-astro-cid-gcn2mc3v>Hardware &amp; Manufacturing</a><a href="/solutions/javascript-security-scanner" data-astro-cid-gcn2mc3v>JavaScript &amp; TypeScript</a> </div> <div data-astro-cid-gcn2mc3v> <p class="label" data-astro-cid-gcn2mc3v>Explore</p> <a href="/learn" data-astro-cid-gcn2mc3v>Learning</a> <a href="/research" data-astro-cid-gcn2mc3v>Research</a> <a href="/blog" data-astro-cid-gcn2mc3v>Blog</a> <a href="/advisories" data-astro-cid-gcn2mc3v>Advisories</a> </div> <div data-astro-cid-gcn2mc3v> <p class="label" data-astro-cid-gcn2mc3v>Company</p> <a href="/about" data-astro-cid-gcn2mc3v>About</a> <a href="/contact" data-astro-cid-gcn2mc3v>Contact</a> <a href="/trust-center" data-astro-cid-gcn2mc3v>Trust Center</a> <a href="/newsroom" data-astro-cid-gcn2mc3v>Newsroom</a> <a href="/recognition" data-astro-cid-gcn2mc3v>Recognition</a> <a href="/pricing" data-astro-cid-gcn2mc3v>Pricing</a> <a href="https://www.corgea.app/login/" data-astro-cid-gcn2mc3v>Log in</a> <a href="/llms.txt" data-astro-cid-gcn2mc3v>LLM site guide</a> <button type="button" class="footer-link" data-open-consent-preferences data-astro-cid-gcn2mc3v>Cookie preferences</button> </div> <div class="footer-newsletter" data-astro-cid-gcn2mc3v> <div class="research-newsletter research-newsletter--footer" data-astro-cid-l6r5txfu> <div class="research-newsletter__copy" data-astro-cid-l6r5txfu> <p class="research-newsletter__label" data-astro-cid-l6r5txfu>Subscribe to our security research</p> <p class="research-newsletter__description" data-astro-cid-l6r5txfu>Get new advisories by email or plug the feed into your RSS reader.</p> </div> <div class="research-newsletter__actions" data-astro-cid-l6r5txfu> <a class="research-newsletter__rss-link" href="/research/rss.xml" target="_blank" rel="noopener noreferrer" aria-label="Open the Corgea research RSS feed" data-astro-cid-l6r5txfu> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" data-astro-cid-l6r5txfu="true" class="lucide lucide-rss"> <path d="M4 11a9 9 0 0 1 9 9"></path><path d="M4 4a16 16 0 0 1 16 16"></path><circle cx="5" cy="19" r="1"></circle> </svg> <span data-astro-cid-l6r5txfu>RSS feed</span> </a> <div class="newsletter-form-container" data-astro-cid-l6r5txfu> <form class="newsletter-form" action="https://app.loops.so/api/newsletter-form/cm4bu30wb03t5eyehwevuh0bq" method="POST" data-astro-cid-l6r5txfu> <input class="newsletter-form-input" placeholder="you@example.com" required type="email" name="newsletter-form-input" aria-label="Email address" data-astro-cid-l6r5txfu> <button type="submit" class="newsletter-form-button" data-astro-cid-l6r5txfu>Subscribe</button> <button type="button" class="newsletter-loading-button" hidden data-astro-cid-l6r5txfu>Please wait...</button> </form> <div class="newsletter-success" hidden data-astro-cid-l6r5txfu> <p class="newsletter-success-message" data-astro-cid-l6r5txfu>Thank you for subscribing!</p> </div> <div class="newsletter-error" hidden data-astro-cid-l6r5txfu> <p class="newsletter-error-message" data-astro-cid-l6r5txfu>Oops! Something went wrong, please try again</p> </div> <button type="button" class="newsletter-back-button" hidden data-astro-cid-l6r5txfu>&larr; Back</button> </div> </div> </div> <script>(function(){const userGroup = "Security Research Newsletter"; const newsletterErrorMessage = "Oops! Something went wrong, please try again"; const newsletterRateLimitMessage = "Too many signups, please try again in a little while"; function submitHandler(event) { event.preventDefault(); var form = event.currentTarget; var container = form.closest('.newsletter-form-container'); if (!container) return; var formInput = container.querySelector('.newsletter-form-input'); var success = container.querySelector('.newsletter-success'); var errorContainer = container.querySelector('.newsletter-error'); var errorMessage = container.querySelector('.newsletter-error-message'); var backButton = container.querySelector('.newsletter-back-button'); var submitButton = container.querySelector('.newsletter-form-button'); var loadingButton = container.querySelector('.newsletter-loading-button'); const rateLimit = () => { errorContainer.hidden = false; success.hidden = true; errorMessage.innerText = newsletterRateLimitMessage; submitButton.hidden = true; formInput.hidden = true; backButton.hidden = false; }; var time = new Date(); var timestamp = time.valueOf(); var previousTimestamp = localStorage.getItem('loops-form-timestamp'); if (previousTimestamp && Number(previousTimestamp) + 60000 > timestamp) { rateLimit(); return; } localStorage.setItem('loops-form-timestamp', timestamp); submitButton.hidden = true; loadingButton.hidden = false; var formBody = 'userGroup=' + encodeURIComponent(userGroup) + '&mailingLists=&email=' + encodeURIComponent(formInput.value); fetch(form.action, { method: 'POST', body: formBody, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }) .then(async (res) => { const data = await res.json().catch(() => ({})); if (res.ok && data.success !== false) { success.hidden = false; errorContainer.hidden = true; form.reset(); return; } errorContainer.hidden = false; success.hidden = true; console.error(data.message || res.statusText || newsletterErrorMessage); errorMessage.innerText = newsletterErrorMessage; }) .catch((error) => { if (error.message === 'Failed to fetch') { rateLimit(); return; } errorContainer.hidden = false; success.hidden = true; if (error.message) errorMessage.innerText = error.message; localStorage.setItem('loops-form-timestamp', ''); }) .finally(() => { formInput.hidden = true; loadingButton.hidden = true; backButton.hidden = false; }); } function resetFormHandler(event) { var container = event.target.parentNode; var formInput = container.querySelector('.newsletter-form-input'); var success = container.querySelector('.newsletter-success'); var errorContainer = container.querySelector('.newsletter-error'); var errorMessage = container.querySelector('.newsletter-error-message'); var backButton = container.querySelector('.newsletter-back-button'); var submitButton = container.querySelector('.newsletter-form-button'); success.hidden = true; errorContainer.hidden = true; errorMessage.innerText = newsletterErrorMessage; backButton.hidden = true; formInput.hidden = false; submitButton.hidden = false; } var formContainers = document.getElementsByClassName('newsletter-form-container'); for (var i = 0; i < formContainers.length; i++) { var formContainer = formContainers[i]; var handlersAdded = formContainer.classList.contains('newsletter-handlers-added'); if (handlersAdded) continue; formContainer.querySelector('.newsletter-form').addEventListener('submit', submitHandler); formContainer.querySelector('.newsletter-back-button').addEventListener('click', resetFormHandler); formContainer.classList.add('newsletter-handlers-added'); } })();</script> </div> </div> </footer> <div class="consent-manager" data-astro-cid-onzc4e62> <aside class="consent-banner card" data-consent-banner aria-live="polite" aria-hidden="true" hidden data-astro-cid-onzc4e62> <p class="consent-kicker" data-astro-cid-onzc4e62>Privacy</p> <h2 data-astro-cid-onzc4e62>Cookies and tracking</h2> <p data-astro-cid-onzc4e62> We use necessary storage to keep the site working. Privacy-friendly, cookieless analytics may run without consent. Optional measurement and marketing tools only run according to your consent choices. </p> <p class="consent-configured" data-astro-cid-onzc4e62> Configured integrations: Google Analytics 4, Google Tag Manager, PostHog. </p> <p class="consent-status" data-consent-status data-consent-locale="en" data-astro-cid-onzc4e62> Choose whether to enable optional consent-based measurement and marketing technologies. </p> <div class="consent-actions" data-astro-cid-onzc4e62> <button class="button button-ghost" type="button" data-consent-open-dialog data-astro-cid-onzc4e62> Customize </button> <button class="button button-ghost" type="button" data-consent-accept-necessary data-astro-cid-onzc4e62> Only necessary </button> <button class="button button-primary" type="button" data-consent-accept-all data-astro-cid-onzc4e62> Accept all </button> </div> </aside> <div class="consent-backdrop" data-consent-backdrop aria-hidden="true" hidden data-astro-cid-onzc4e62></div> <section class="consent-dialog card" data-consent-dialog role="dialog" aria-modal="true" aria-labelledby="consent-dialog-title" aria-hidden="true" hidden data-astro-cid-onzc4e62> <div class="consent-dialog-header" data-astro-cid-onzc4e62> <div data-astro-cid-onzc4e62> <p class="consent-kicker" data-astro-cid-onzc4e62>Preferences</p> <h2 id="consent-dialog-title" data-astro-cid-onzc4e62>Manage your tracking choices</h2> </div> <button class="consent-close" type="button" data-consent-close-dialog aria-label="Close cookie preferences" data-astro-cid-onzc4e62> Close </button> </div> <div class="consent-options" data-astro-cid-onzc4e62> <label class="consent-option" data-astro-cid-onzc4e62> <div data-astro-cid-onzc4e62> <strong data-astro-cid-onzc4e62>Necessary</strong> <p data-astro-cid-onzc4e62>Required for consent storage and core website behavior. These are always enabled.</p> </div> <input type="checkbox" checked disabled data-astro-cid-onzc4e62> </label> <label class="consent-option" data-astro-cid-onzc4e62> <div data-astro-cid-onzc4e62> <strong data-astro-cid-onzc4e62>Measurement</strong> <p data-astro-cid-onzc4e62>Helps us understand site usage, performance, and session recordings with Google Analytics and PostHog.</p> </div> <input type="checkbox" data-consent-toggle="measurement" data-astro-cid-onzc4e62> </label> <label class="consent-option" data-astro-cid-onzc4e62> <div data-astro-cid-onzc4e62> <strong data-astro-cid-onzc4e62>Marketing</strong> <p data-astro-cid-onzc4e62>Supports ad attribution and audience measurement with LinkedIn and consent-aware tags managed through Google Tag Manager.</p> </div> <input type="checkbox" data-consent-toggle="marketing" data-astro-cid-onzc4e62> </label> </div> <div class="consent-dialog-actions" data-astro-cid-onzc4e62> <button class="button button-ghost" type="button" data-consent-accept-necessary data-astro-cid-onzc4e62> Only necessary </button> <button class="button button-primary" type="button" data-consent-save-preferences data-astro-cid-onzc4e62> Save preferences </button> </div> </section> </div> <script type="module" src="/_astro/ConsentManager.astro_astro_type_script_index_0_lang.D5ZSEAhd.js"></script> <script type="module" src="/_astro/PostHogCtaTracking.astro_astro_type_script_index_0_lang.D4c12oBz.js"></script> <script> (() => { if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; const targets = document.querySelectorAll('[data-scroll-fade]'); if (!targets.length) return; const observer = new IntersectionObserver((entries) => { for (const entry of entries) { if (!entry.isIntersecting) continue; entry.target.classList.add('is-visible'); observer.unobserve(entry.target); } }, { threshold: 0.16, rootMargin: '0px 0px -8% 0px' }); targets.forEach((el) => observer.observe(el)); })(); </script> </body> </html>