Learn which audit layers actually help Clojure teams, including linting, dependency review, secret scanning, container checks, dynamic probing, and focused manual review around high-risk flows.
Security auditing: Repeated, structured inspection of code, dependencies, runtime artifacts, and exposed behavior to discover weaknesses before an attacker or incident does.
One tool will not audit a Clojure application. Strong auditing is layered:
The goal is not maximal tool count. The goal is enough coverage that one class of weakness does not stay invisible for months.
For Clojure code, clj-kondo is often the most practical static baseline because it is fast, scriptable, and easy to keep in CI. Linters and style tools are not dedicated security scanners, but they still help surface:
They are best treated as hygiene tooling that keeps the codebase readable enough for real security review.
A Clojure service inherits risk from:
That means dependency auditing should include both application coordinates and the runtime artifact that ships. Teams often use a mix of:
The point is not which vendor you choose. It is that “we only reviewed our own code” is not a real security posture.
A committed secret is one of the fastest ways to create a lasting breach path. Add secret scanning for:
This is especially important in Clojure repos because configuration and data fixtures often live in EDN and can look deceptively harmless in review.
Once the service is running, probe the exposed behavior:
ZAP remains a practical dynamic testing tool for web applications, but even a smaller custom probe suite is useful if it targets the real attack surface of the product.
No scanner fully understands:
That is where manual review matters most. Security auditing is strongest when humans spend their time on the parts scanners do not understand well.
A practical CI audit pipeline might include:
1name: security-checks
2on: [push, pull_request]
3jobs:
4 review:
5 runs-on: ubuntu-latest
6 steps:
7 - uses: actions/checkout@v4
8 - uses: actions/setup-java@v4
9 with:
10 distribution: temurin
11 java-version: "21"
12 - name: "Lint Clojure"
13 run: "clj-kondo --lint src:test"
14 - name: "Run tests"
15 run: "clojure -M:test"
16 - name: "Scan container image"
17 run: "trivy image myapp:ci"
The exact tools will vary. The durable pattern is: make auditing automatic enough that it happens on every change, and focused enough that the signal still matters.
Tools find patterns. They do not understand all business abuse paths.
The container, JVM, and OS layers matter too.
Unreviewed alerts are only slightly better than no alerts.
Security review is strongest when it runs continuously and locally in development, not only at the end.
Use lightweight static checks on every change, dependency and container scanning in CI, secret scanning on diffs and history, and dynamic testing for the live surface. Then spend human review time on high-risk domain behavior such as authorization, multi-tenancy, and exports. In Clojure, the best audit setup is not the loudest. It is the one that makes the right failures visible soon enough to fix them cheaply.