Tutorial: Scanning a Node.js App
This tutorial walks through scanning a typical Express.js application from start to finish.
Sample Application
Section titled “Sample Application”Consider an Express app with:
- PostgreSQL database (via
pglibrary) - JWT authentication (via
jsonwebtoken) - Password hashing (via
bcrypt) - File uploads (via
multer) - Redis sessions
Step 1: Run the Scan
Section titled “Step 1: Run the Scan”fleet scan --path ./my-express-app --output pretty --sbom --cbomStep 2: Review the SBOM
Section titled “Step 2: Review the SBOM”The scanner parses package-lock.json (or yarn.lock) and generates a CycloneDX 1.6 SBOM. Check the component count:
SBOM: 847 components from npm ecosystemEach component is identified by PURL (Package URL):
pkg:npm/express@4.18.2pkg:npm/jsonwebtoken@9.0.2pkg:npm/bcrypt@5.1.1Step 3: Review the CBOM
Section titled “Step 3: Review the CBOM”The CBOM inventories all crypto primitives found in your source code and dependencies:
CBOM: 28 crypto primitives (24 approved, 2 deprecated, 2 prohibited)Common findings in Node.js apps:
- MD5 (prohibited) — often in legacy cache key generation
- SHA-1 (deprecated) — sometimes in HMAC for webhook verification
Step 4: Triage Findings
Section titled “Step 4: Triage Findings”Typical findings for an Express app:
| Finding | Status | Action |
|---|---|---|
CRYPTO-01-R1 — MD5 in utils/hash.js:15 | fail | Fix: replace with SHA-256 |
NET-DB-02-R1 — DB password in config.js:8 | fail | Fix: use env vars |
AUTH-01-R1 — bcrypt cost factor 10 | pass | No action needed |
NET-SVC-01-R1 — Auth middleware present | needs_review | Review: verify all routes covered |
NET-SVC-02-R1 — Rate limiting | needs_review | Review: check express-rate-limit config |
VH-ID-01-R1 — No security.txt | fail | Fix: create .well-known/security.txt |
Step 5: Fix the Failures
Section titled “Step 5: Fix the Failures”Replace MD5
Section titled “Replace MD5”// Beforeconst crypto = require('crypto');const hash = crypto.createHash('md5').update(data).digest('hex');
// Afterconst hash = crypto.createHash('sha256').update(data).digest('hex');Move credentials to environment
Section titled “Move credentials to environment”// Beforeconst pool = new Pool({ connectionString: 'postgres://admin:secret@db:5432/mydb' });
// Afterconst pool = new Pool({ connectionString: process.env.DATABASE_URL });Add security.txt
Section titled “Add security.txt”Create .well-known/security.txt:
Contact: mailto:security@yourcompany.comPreferred-Languages: enCanonical: https://yourapp.com/.well-known/security.txtExpires: 2027-12-31T23:59:59zStep 6: Re-scan and Generate Report
Section titled “Step 6: Re-scan and Generate Report”fleet scan --path . --output pretty --report cra-report.mdVerify failures are resolved, then review the Module A report for completeness.