Security Post-it #6 – Software Security Testing for JavaScript and TypeScript

In this short security post-it, I explain how to secure your JavaScript and TypeScript code using open-source tools: SAST and SCA.

Nov 3, 2022 by Nicolas Béguier

We all agree that you have to secure your code. On the other hand, it is not always easy to know where to start and identify what is effective. I will present here the SAST and SCA implementations on your JavaScript and TypeScript repositories.

Oh wait, I forgot to tell you. This is to build it yourself on your CI/CD or in your pre-commit hooks, with open-source tools.

What are SAST and SCA ?

Static Application Security Testing (SAST) is used to scan the code you write for security vulnerabilities and Software Composition Analysis (SCA) is used to scan your dependencies for security vulnerabilities.

When we look at these two technologies side by side, it becomes clear that both are necessary for an effective and secure development approach. SAST is more helpful for the code you write, while SCA is effective at analyzing the open-source software your organization uses, as well as its dependencies. These two technologies address security issues early and often during the development cycle.

In my opinion, SAST should be both asynchronous and synchronous. Blocking CI/CD pipelines to prevent unsecured code is great, but you need to specify exceptions and false-positive management. Running it asynchronously permits your security team to read reports and be alerted in real-time for potential vulnerabilities.
SCA must be asynchronous only, otherwise you will only be alerted when new code is pushed. Dead repositories are full of vulnerable dependencies. Run it somewhere else but continuously, and why not use a tool to create Pull Requests automatically, like Renovabot.

Static Application Security Testing (SAST)

Today, if you want really effective security coverage, you need to use semgrep. I can propose njsscan which relies on semgrep with additionnal rules.

Njsscan focuses only on server side javascript/html code, while you are interested in client-side security (Ex: DOM-XSS, postmessage abuse, open redirect) and extended rules.

Install

# Semgrep
$ pip install semgrep
# Njsscan
$ pip install njsscan

Audit with semgrep

Human readable output # Paranoid mode: OWASP Top Ten + some of my favorites
$ semgrep --config=r/javascript.browser.security.insufficient-postmessage-origin-validation.insufficient-postmessage-origin-validation --config=r/javascript.lang.security.audit.incomplete-sanitization.incomplete-sanitization --config=r/javascript.browser.security.dom-based-xss.dom-based-xss --config=r/typescript.react.security.audit.react-css-injection.react-css-injection --config=r/typescript.react.security.audit.react-href-var.react-href-var --config=p/owasp-top-ten __CODE_DIRECTORY__
# This ruleset is intended to produce low false positives, and safe for use in CI/CD pipelines.
$ semgrep --config=p/ci __CODE_DIRECTORY__

Work with a JSON output $ semgrep --config=p/ci __CODE_DIRECTORY__ -o /tmp/semgrep.json --json $ cat /tmp/semgrep.json | jq .results

Audit with njsscan

Human readable output $ njsscan __CODE_DIRECTORY__
Work with a JSON output $ njsscan __CODE_DIRECTORY__ -o /tmp/njsscan.json --json $ cat /tmp/njsscan.json | jq .nodejs $ cat /tmp/njsscan.json | jq .templates

Example

Let's take an example : https://github.com/juice-shop/juice-shop - "OWASP Juice Shop: Probably the most modern and sophisticated insecure web application" # Clone the vulnerable repo in /tmp.
$ git clone https://github.com/juice-shop/juice-shop /tmp/juice-shop
# Scan it with semgrep, in paranoiac mode.
$ semgrep --config=r/javascript.browser.security.insufficient-postmessage-origin-validation.insufficient-postmessage-origin-validation --config=r/javascript.lang.security.audit.incomplete-sanitization.incomplete-sanitization --config=r/javascript.browser.security.dom-based-xss.dom-based-xss --config=r/typescript.react.security.audit.react-css-injection.react-css-injection --config=r/typescript.react.security.audit.react-href-var.react-href-var --config=p/owasp-top-ten /tmp/juice-shop/

/tmp/juice-shop/data/static/codefixes/unionSqlInjectionChallenge_3.ts
javascript.express.security.injection.tainted-sql-string.tainted-sql-string
Detected user input used to manually construct a SQL string. This is usually bad practice because manual construction could accidentally result in a SQL injection. An attacker could use a SQL injection to steal or modify contents of the database. Instead, use a parameterized query which is available by default in most database engines. Alternatively, consider using an object-relational mapper (ORM) such as Sequelize which will protect your queries.
Details: https://sg.run/66ZL

10┆ ... criteria}%' OR description LIKE '%${criteria}%') AND deletedAt IS NULL) ORDER BY name`) ...
[shortened a long line from output, adjust with --max-chars-per-line]
⋮┆----------------------------------------

Ran 471 rules on 979 files: 41 findings.

Does it work on my CI ?

https://semgrep.dev/docs/semgrep-ci/running-semgrep-ci-without-semgrep-app/

There is documentation for:
  • GitHub Actions
  • GitLab CI/CD
  • Jenkins
  • BitBucket Pipelines
  • CircleCI
  • Buildkite

Software Composition Analysis (SCA)

Depscan by AppThreat is a fully open-source security audit for project dependencies based on known vulnerabilities and advisories.

cdxgen is extracting all dependencies from npm-shrinkwrap.json, package-lock.json, pnpm-lock.yaml, yarn.lock, rush.js, bower.json, .min.js, and transitive dependencies.

It doesn't work perfectly for all languages, but for JavaScript it works great.

Install

# Install cdxgen in /tmp/, use -g for a global install instead of --prefix /tmp/
$ npm install --prefix /tmp/ @appthreat/cdxgen
# Not very clean, but temporary
$ PATH=$PATH:/tmp/node_modules/.bin
$ pip install appthreat-depscan

Audit

Human readable output $ cdxgen -o /tmp/bom.json __CODE_DIRECTORY__ $ depscan --bom /tmp/bom.json -o /tmp/depscan.json
Work with a JSON output $ cat /tmp/depscan.json | jq .

Example

In this example, I'm using this random GitHub repository: https://github.com/Faten4/HW-Search # Clone the vulnerable repo in /tmp.
$ git clone https://github.com/Faten4/HW-Search /tmp/HW-Search
$ cdxgen -o /tmp/bom.json /tmp/HW-Search/ $ depscan --bom /tmp/bom.json -o /tmp/depscan.json
Dependency Scan Results (nodejs)
╔════════════════╤═══════════╤═══════════════════════╤═════════╤═════════════╤══════════╤═══════╗
║ Id             │ Package   │ Insights              │ Version │ Fix Version │ Severity │ Score ║
╟────────────────┼───────────┼───────────────────────┼─────────┼─────────────┼──────────┼───────╢
║ CVE-2021-3803  │ nth-check │ ℹ Indirect dependency │ <2.0.1  │ 2.0.1       │ HIGH     │   7.5 ║
╟────────────────┼───────────┼───────────────────────┼─────────┼─────────────┼──────────┼───────╢
║ CVE-2022-40215 │ tabs      │ 🎯 Direct usage       │ <=3.7.1 │             │ MEDIUM   │   5.4 ║
╟────────────────┼───────────┼───────────────────────┼─────────┼─────────────┼──────────┼───────╢
║ CVE-2022-33154 │ schema    │ ℹ Indirect dependency │ <1.13.1 │ 1.13.1      │ MEDIUM   │   5.4 ║
╚════════════════╧═══════════╧═══════════════════════╧═════════╧═════════════╧══════════╧═══════╝

Does it work on my CI ?

https://github.com/appthreat/dep-scan#integration-with-ci-environments

There is documentation for:
  • GitHub Actions
But more with the shiftleft project.

Conclusion

You don’t necessarily need an expensive code scanner like Snyk or CherckMarx, you can build it yourself. If you put it in pre-commit hooks, CI/CD and asynchronous you will have a complete view of your application security risk and earn awareness of the developers about security concerns.
At Tandem Technology, we'll help you improve your development practices during a workshop to harden your code repository.

If you enjoyed this story, please recommend and share to help others find it! Feel free to contact me if you have any questions.