Dependency Management and Security

Chris Choi

Security in web development touches all avenues of the field from requests, session hijacking, SQL injections and many more mentioned on the Open Web Application Security Project (OWASP). Many buffers now exist between developers and situations where malicious users can capitalize on dependency management oversights. Hackers are resourceful in their exploits of known (and sometimes unknown) vulnerabilities.

As one of our developers Rob mentions on his blog post, “A Newer Dev’s Perspective on Learning OWASP”,

After developing a firm understanding of OOP, TDD, and Rails, I found myself conflicted about all the directions I could go with my learning.

Learning Rails and its best practices, conventions, and methodologies is a huge undertaking in itself. Libraries like Rails, Angular, Next, React, and jQuery provide huge benefits with helpers, cli commands to generate new files, speed up development processes, and have established methodologies that companies with millions of users rely on. Along with the benefits of receiving great tooling to be a more productive developer, frameworks like Rails provides great security measures to shield developers from things like XSS, session hijacking, and many more that we still see today.

So why mention frameworks and libraries? Most of the these libraries are not just one large codebase, but are a ecosystem of dependencies used to support the library. For example, a React application scaffolded by create-react-app 2.1 is shipped with 1,568 dependencies. Keeping track of the security state of each dependency is difficult as new CVEs pop up each passing moment! One can cover some of their bases with tools like npm audit for JavaScript packages and bundler-audit for Ruby gems respectfully. While automated security tools are great, they do have pitfalls. Many tools rely on packages being reported as CVEs so that such scanners can check to see if such version is reported as a CVE on the web.

An example of how auditing looks with JS, in this case, a freshly generated create-react-app via yarn audit:

example1 [master●] $ yarn audit
yarn audit v1.21.1
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ moderate      │ Cross-Site Scripting                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ serialize-javascript                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=2.1.1                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ react-scripts                                                │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ react-scripts > terser-webpack-plugin > serialize-javascript │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://www.npmjs.com/advisories/1426                        │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ moderate      │ Cross-Site Scripting                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ serialize-javascript                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=2.1.1                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ react-scripts                                                │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ react-scripts > webpack > terser-webpack-plugin >            │
│               │ serialize-javascript                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://www.npmjs.com/advisories/1426                        │
└───────────────┴──────────────────────────────────────────────────────────────┘
2 vulnerabilities found - Packages audited: 904865
Severity: 2 Moderate
✨  Done in 2.21s.

As one can see, a freshly generated create-react-app is shipped with two moderate level vulnerabilities. These vulnerabilities deal with the sanitization of serialized regular expressions(REGEX). While these can be patched individually, it is important to note that dependency and CVE quantities are directly correlated. More dependencies means more CVEs to deal with

A more extreme example is an incident where dependencies are hijacked by malicious developers, creating backdoors in applications for harvesting sensitive user information. We covered one such incident in our blog post, The Case for 2FA, Post Rest-client Gem CVE. A malicious developer was able to hijack a maintainer account and push code that created a backdoor to harvest credentials. A almost parallel situation can be seen in the npm landscape with a simple React datepicker library, which many reach for as jQuery datepicker libraries can be seen on most websites.

2FA is not required for maintainer accounts for most popular package managers, so the possibility of such hijackings up to the security of the maintainer’s accounts. Being at the mercy of whether such an event happens or not isn’t the professional thing to do, developers should be proactive to protect and secure user credentials. Managing dependencies on all fronts should not be delegated to a side chore, but as a important task that should not be overlooked.

An excellent report The state of JavaScript frameworks security report 2019 created by synk.io illustrates the situation of many of the top JavaScript frameworks and libraries that have security vulnerabilities on initial scaffold, and some of which that aren’t even picked up with most cli auditors. Many would say that jQuery is a thing of the past, but as revealed by the report,

jQuery was downloaded more than 120 million times in the last 12 months and according to W3Techs, jQuery v1.x is used in 84% of all websites using jQuery, which have four medium severity XSS vulnerabilities affecting it. In fact, if you’re not using jQuery v3.4.0 and above, which is true for the majority of jQuery users, then you are using a version that includes security vulnerabilities.

Projects are abandoned and not properly maintained, as these projects are neglected, so are the vulnerabilities that will become publicly known. Websites use popular CSS libraries like Bootstrap that is dependent on jQuery, this includes many of the jQuery and Bootstrap plugins that users will add to their project. Each plugins has its own dependencies…the pattern should be obvious by now.

Security conscious developers can create robust code covering the swathes of insecure practices existing in web development. When introducing new dependencies the developer did not write, consciousness of the potential security risks they carry can be the difference between a slow and swift response. By utilizing security CLI tools like npm-audit, yarn audit, and bundle-audit we can quickly pounce on known vulnerabilities. Using these tools can secure us from known vulnerabilities, but by being a little more reserved when introducing dependencies or libraries, we can mitigate some risk caused by unreported CVEs. Turnaround time and using dependencies that have active maintainers with a strong community can provide some confidence.