# Static Application Security for Nodejs (with Gitlab CI)

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](/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:

```
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.

```
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!