What are some tools and techniques for identifying security vulnerabilities in JavaScript code?
TL;DR
Use complementary layers: threat modeling and manual review for design flaws; linters and static analysis for risky data flows and APIs; dependency and secret scanning for supply-chain exposure; authorization-focused tests; and dynamic tools such as OWASP ZAP or Burp Suite against an authorized running environment. No scanner proves an application secure. Prioritize findings by exploitability and impact, verify them manually, and retest the fix.
Do not run active scans against systems you do not own or have permission to test. Use controlled test data and avoid placing real credentials in scan configuration or reports.
Start with the application's threats
Inventory assets, entry points, trust boundaries, roles, and third-party integrations. For a document-sharing feature, ask concrete questions:
- Can one user change an ID and read another user's document?
- Is untrusted text inserted into an HTML, URL, CSS, SQL, or shell context?
- Can an uploaded file execute or expose private metadata?
- Can a cross-site request perform a state-changing action?
- Are secrets or private responses shipped to the browser or logs?
This tells you which automated and manual checks matter. A dependency scan cannot find a missing ownership check in application code.
Static analysis and linting
Linters and static application security testing can flag patterns such as dynamic code execution, unsafe DOM sinks, weak randomness, path traversal, and unsafely constructed queries. Examples include ESLint security plugins, Semgrep, CodeQL, and commercial SAST platforms.
Treat a rule match as a lead, not a confirmed vulnerability. Tune rules to the codebase, review suppressions, and keep analysis in CI so new findings are visible in the change that introduced them.
Dependencies, provenance, and secrets
- Package-manager audits, Dependabot, Renovate, Snyk, or similar services match dependency versions to known advisories.
- Lockfiles and an SBOM make the resolved dependency graph reviewable.
- Secret scanners detect credentials committed to source, history, build output, and configuration.
A reported vulnerable package may be unreachable in your application, while an unreported malicious or compromised package may still be dangerous. Verify the dependency path, affected behavior, available patch, and runtime exposure. If a real secret was committed, remove it from use and rotate it; deleting the current file is not enough.
Dynamic and interactive testing
OWASP ZAP and Burp Suite inspect a running web application and can crawl, proxy, fuzz, and scan requests. Run active attacks only against an explicitly authorized environment that can tolerate the traffic and data mutations. Authenticate as several roles and test object-level and function-level authorization manually; scanners often cannot infer the intended access policy.
Browser developer tools are also valuable for checking CSP violations, cookie attributes, CORS behavior, exposed source maps, storage, and actual request data.
Security tests and review
Turn important boundaries into repeatable tests:
test('a member cannot read another workspace document', async () => {const response = await request(app).get('/documents/private-document').set('Authorization', memberToken);expect(response.status).toBe(404);});
Review authentication, authorization, parameterized queries, context-aware output handling, file handling, redirects, outbound requests, cryptography, error disclosure, logging, and rate limits. Input validation is useful, but there is no universal “sanitize” operation: SQL binding, HTML sanitization, output encoding, and shell avoidance are different controls.
A practical workflow
- Define the threat and reproduce the suspected issue safely.
- Confirm whether the input crosses a trust boundary and reaches a sensitive sink or action.
- Assess affected users, required privileges, and realistic impact.
- Fix the control at the trusted boundary, not only in browser code.
- Add a regression test and rerun the relevant static, dependency, or dynamic check.
- Record accepted risk and time-bound exceptions rather than silently suppressing findings.
Further reading
- OWASP Web Security Testing Guide
- OWASP Code Review Guide
- OWASP ZAP
- Burp Suite documentation
- npm audit
- GitHub CodeQL documentation