# Static Application Security for Nodejs (with Gitlab CI)

- Link: https://www.agilicus.com/static-application-security-testing-sast-and-nodejs-with-gitlab-ci/
- Published: 2019-04-23T12:45:00+00:00
- Author: Don Bowman

SAST. Its a thing. [Take the test](https://www.recoveryzone.com/tests/sex-addiction/SAST/index.php)
to see if you need it. 🙂 OK, not that SAST, the one that relates to security silly.
Let’s talk about integrating static application security for nodejs from our Gitlab
CI as part of a [Defense In Depth](https://www.agilicus.com/blog/defense-in-depth/)
strategy.

So I’ve been using [clair](https://github.com/coreos/clair) from [coreos](https://github.com/coreos).
Its pretty awesome, but, to my chagrin, it does not cover python / node / go / ruby/…,
the majority of the upstream culprits. (It focuses on apk/rpm/deb). So you can get
a false sense of security by running it. It [shocked](https://blog.donbowman.ca/2018/06/02/to-know-and-do-nothing-or-to-not-know-which-is-worse/)
me when I did my wiki, but then I fixed those issues and moved on and forgot. So
when it came time to do my first node.js ‘express’ app, I ran it, got no hits, and
was pleased with myself. Static application security for nodejs achieved?

Not so fast. Turns out you need to look a bit harder, tools like [snyk](https://snyk.io/org/don/),
[retire](https://retirejs.github.io/retire.js/), [audit](https://www.npmjs.com/package/auditjs).
So I picked two (retire, audit) and added them to my CI pipeline, as below:

    ```language-yaml
    stage: scan
      artifacts:
        name: "$CI_PROJECT_PATH-$CI_COMMIT_REF_NAME"
        paths:
          - reports/
      script: |
        echo Analyse container $CI_REGISTRY/$CI_PROJECT_PATH:$CI_COMMIT_SHA for vulnerability
        docker tag $CI_REGISTRY/$CI_PROJECT_PATH:$CI_COMMIT_SHA $CI_PROJECT_PATH:$CI_COMMIT_SHA
        clairctl analyze -l -n --log-level debug $CI_PROJECT_PATH:$CI_COMMIT_SHA
        echo Generate JSON report
        clairctl report -l -f json $CI_PROJECT_PATH:$CI_COMMIT_SHA
        echo Generate HTML report
        clairctl report -l -f html $CI_PROJECT_PATH:$CI_COMMIT_SHA
        docker tag $CI_PROJECT_PATH:$CI_COMMIT_SHA scannee
        docker build -t scanner -f Dockerfile.scan .
        docker run --rm scanner retire --path /usr/src/app > reports/retire.js.txt 2>&1 || true
        docker run --rm scanner retire --path /usr/local/lib/node_modules/npm >> reports/retire.js.txt 2>&1 || true
        docker run -w /usr/src/app --rm scanner auditjs -r >> reports/audit.js.txt || true
    ```

Now, unlike clair, these actually need to run in the image, or maybe with it mounted
somehow. So I created this very simple Dockerfile. It inherits from ‘scannee’, which
I tagged the main image as above.

Now, something else I found ‘exciting’. You see that ‘USER root’? Well the origin
image (scannee) has a ‘USER nonprivileged’. So here I am increasing my privilege,
I did not think you could do that. Hmm.

    ```language-docker
    FROM scannee
    ENV NODE_ENV "production"

    WORKDIR /usr/src/app

    USER root

    # See https://github.com/npm/uid-number/issues/3 for why the 'set unsafe-perm'
    RUN npm config set unsafe-perm true  \
     && npm install -g retire \
     && npm install -g auditjs
    ```

Now my CI stage above scans (with clair), then builds a child container augmenting
with retire and audit, then runs them. The original layer is unchanged, untouched.
I can do my static application security for nodejs as-is.

I thought this was neat, you probably thought it was old hat.

But, it found me another hundred or so issues to dig into. And this is from node:
9.11.0-alpine, its not like that is old!
