Safeguard
Vulnerability Analysis

CVE-2020-7676: XSS in vue-template-compiler

CVE-2020-7676 is an XSS flaw in vue-template-compiler (pre-2.6.12) that lets attacker-controlled templates bypass URI sanitization. Impact, fix, and remediation.

Nayan Dey
Security Researcher
7 min read

CVE-2020-7676 is a cross-site scripting (XSS) vulnerability in vue-template-compiler, the npm package responsible for turning Vue.js 2.x template strings into JavaScript render functions. Because vue-template-compiler sits in the build pipeline for .vue single-file components, server-side rendering (SSR) setups, and any application that compiles Vue templates at runtime, a flaw in how it sanitizes attribute values has real consequences: an attacker who can influence template content — through a CMS field, a user-editable component, a template preview feature, or an SSR pipeline that renders untrusted markup — could get the compiler to emit a render function that executes attacker-controlled JavaScript in a victim's browser. That's the textbook definition of stored or DOM-based XSS, and it's exactly the class of bug CVE-2020-7676 falls into.

The root issue lives in the compiler's attribute-sanitization logic. Vue's template compiler has long included guards against dangerous URI schemes (most notably javascript:) in bound attributes like href and xlink:href, precisely to stop template authors — or attackers who control template content — from smuggling executable script into a rendered link or SVG element. Public write-ups of this advisory describe the guard as bypassable using crafted whitespace or control-character sequences around the disallowed scheme, letting a malicious URI value slip past the check and reach the DOM intact. The net effect is that content which should have been neutralized during compilation instead survives into the render function and executes when the component mounts.

Affected Versions and Components

  • Package: vue-template-compiler (the standalone compiler package published alongside Vue.js 2.x, used by vue-loader, vueify, SSR bundle setups, and any tooling that pre-compiles .vue files or raw template strings).
  • Affected releases: versions prior to 2.6.12.
  • Fixed version: 2.6.12, which aligns with the corresponding Vue 2.6.12 core release.
  • Related component: because vue-template-compiler's version must match the vue runtime version it's paired with, projects pinned to an older vue 2.x release commonly carry a matching pre-2.6.12 vue-template-compiler as a transitive or direct dependency — this is the most common way teams end up exposed without directly depending on the compiler themselves.
  • Not affected: Vue 3.x, which replaced vue-template-compiler with @vue/compiler-sfc and a different compilation pipeline.

The realistic exposure window is narrower than "any Vue app." The vulnerability matters most where template content itself — not just data bound into a fixed template — is influenced by an untrusted party: dynamic component authoring tools, low-code/CMS builders that let users write Vue templates, SSR services that compile templates supplied by tenants, or internal tooling that renders user-submitted snippets. A typical app that ships developer-authored, static .vue files compiled at build time has a much smaller practical attack surface, though it's still good hygiene to patch.

CVSS, EPSS, and KEV Context

Public vulnerability databases classify CVE-2020-7676 as a Medium-severity issue, consistent with the standard scoring pattern applied to reflected/DOM-based XSS in a browser context: network attack vector, low attack complexity, no privileges required, but requiring user interaction and a scope change (the impact crosses from the vulnerable compiler into the rendering browser context), with limited confidentiality and integrity impact and no availability impact. NVD lists a CVSS v3.x base score in that Medium band (commonly cited as 6.1) rather than a Critical or High rating — reflecting that exploitation depends on an attacker first getting control over template content that gets compiled, not on a purely remote, unauthenticated path into a stock deployment.

EPSS (Exploit Prediction Scoring System) data for this CVE has stayed low, which lines up with its nature: it's a build-time/compile-time sanitization gap in a front-end tooling package rather than an internet-facing service vulnerability that scanners and botnets probe directly. It's the kind of CVE that matters far more to supply-chain and dependency-hygiene tracking than to perimeter security monitoring.

CVE-2020-7676 is not listed in CISA's Known Exploited Vulnerabilities (KEV) catalog. There's no public evidence of active, widespread exploitation in the wild — this is a vulnerability class (XSS in a JS build tool's sanitizer) that's more commonly caught by dependency scanning and code review than by incident response.

Disclosure Timeline

  • Vulnerable state: all vue-template-compiler releases prior to 2.6.12 shipped with the incomplete URI-scheme sanitization described above.
  • Fix: the Vue core team shipped vue-template-compiler 2.6.12, correcting the attribute-sanitization bypass, as part of the broader Vue 2.6.12 release.
  • Public disclosure: the issue was assigned CVE-2020-7676 and published to NVD and downstream advisory feeds (GitHub Security Advisories, Snyk, npm audit databases) in 2020, making it visible to standard software composition analysis (SCA) tooling from that point forward.
  • Current status: the advisory has been stable for years with no revisions indicating renewed exploitation activity or a bypass of the 2.6.12 fix.

Because Vue 2.x has since entered maintenance mode (with Vue 2's official end-of-life having passed), teams still running Vue 2 should treat any unpatched compiler-level CVE like this one as effectively permanent risk unless explicitly remediated — there's no expectation of further hardening from upstream beyond critical fixes.

Remediation Steps

  1. Identify exposure. Run npm ls vue-template-compiler (or the Yarn/pnpm equivalent) across every service and front-end package to find both direct and transitive references, since it's frequently pulled in indirectly via vue-loader or a pinned vue version.
  2. Upgrade to 2.6.12 or later. Bump vue-template-compiler to at least 2.6.12, and keep it version-matched with your vue package — mismatched compiler/runtime versions in Vue 2.x can cause subtle rendering bugs, so update both together and re-run your build.
  3. Re-audit templates that render untrusted content. If your application compiles user-supplied or tenant-supplied template strings at runtime (dynamic component builders, CMS-style rendering, SSR-as-a-service), don't rely on the compiler's sanitizer as your only defense. Add an explicit allowlist for URI schemes and HTML structure before content ever reaches the compiler, and consider sandboxing or output-encoding as a second layer.
  4. Check for pinned or vendored copies. Monorepos and older CI pipelines sometimes vendor a specific compiler version or lock it via resolutions/overrides. Confirm those pins aren't silently holding back the patched version after your package.json update.
  5. Re-run SCA and lockfile diff checks. After upgrading, regenerate lockfiles and re-scan with your SCA tool to confirm the pre-2.6.12 version no longer appears anywhere in the dependency tree, including in build-time-only devDependencies that some scanners skip by default.
  6. Plan the Vue 2 → Vue 3 migration where feasible. Since Vue 2's compiler architecture has been fully replaced in Vue 3 (@vue/compiler-sfc), migrating removes this entire class of legacy-compiler risk rather than just this one CVE.

How Safeguard Helps

CVE-2020-7676 is a good example of why dependency-level visibility has to extend into build tooling, not just runtime libraries — vue-template-compiler doesn't ship in most production bundles, so teams that only scan deployed artifacts can miss it entirely. Safeguard's software supply chain security platform is built to close exactly that gap.

  • Full dependency graph coverage, including devDependencies and transitive packages. Safeguard maps direct and transitive dependencies across your repos — catching a stale vue-template-compiler pulled in through vue-loader or an old vue pin, even when it never appears in a production bundle.
  • Continuous CVE and advisory matching. As new CVEs, GitHub Security Advisories, and NVD entries publish, Safeguard automatically correlates them against your actual dependency inventory, so a Medium-severity, non-KEV finding like this one still surfaces instead of getting lost under higher-CVSS noise.
  • Context-aware risk prioritization. Rather than treating every XSS CVE the same, Safeguard factors in CVSS, EPSS trend, KEV status, and reachability — helping teams recognize that a build-tool XSS bug in a template-authoring feature deserves different urgency than a template that's purely static and developer-authored.
  • Policy-driven remediation workflows. Safeguard can enforce minimum version policies (e.g., blocking merges that reintroduce vue-template-compiler < 2.6.12), generate remediation tickets automatically, and verify the fix lands in the lockfile — not just in package.json.
  • SBOM generation and audit trail. For teams under SOC 2 or similar compliance obligations, Safeguard's SBOM and vulnerability-history tracking provide the evidence trail auditors expect: when the vulnerable version was introduced, when it was flagged, and when remediation shipped.

Individually, CVE-2020-7676 is a contained, well-understood, Medium-severity bug with a clear fix. The bigger lesson is structural: front-end build tooling is part of your software supply chain, and vulnerabilities there hide in places traditional runtime-focused scanning doesn't look. Safeguard is built to make sure they don't stay hidden.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.