Project · open source
DIRA: a zero-dependency security scanner for Python and JavaScript codebases
One command-line tool that looks for hardcoded secrets, known vulnerabilities in dependencies, insecure configuration, and license risk — then writes the findings out in a format a CI system can read.
What it is
DIRA is a Python command-line tool that audits a codebase for a specific set of security problems and reports what it finds. It runs on Python 3.9 or newer and has no runtime dependencies — nothing to install beyond the tool itself, and nothing in its own dependency tree to audit. That constraint is the main design decision behind the project, and most of the implementation work follows from it: lockfile parsing, entropy calculation, SBOM serialisation, and report rendering are all written against the standard library rather than pulled in.
The reason for the constraint is practical. A security scanner that arrives with a large dependency tree of its own is awkward to justify to the people most likely to want it, and awkward to add to a build that is already slow. A single-artifact tool with nothing underneath it can be dropped into a pre-commit hook or a CI job without an argument about supply chain.
It is licensed MIT and developed in the open at github.com/Yusuf-Gadelrab/dira.
What it checks
DIRA runs a set of independent checks over a directory and merges their output into one report. Each check is deliberately narrow, because a check that tries to be clever produces findings nobody trusts.
Secrets
Twenty-four credential patterns for provider formats that have a recognisable shape — AWS keys, Stripe, OpenAI, Anthropic, GitHub, GCP, Slack, npm tokens, database connection strings, PEM private keys — plus one generic high-entropy rule gated on Shannon entropy so that a long random-looking string is only reported when it is genuinely unlikely to be a word. Every matched value is redacted in the output, which is what makes a report safe to attach to a ticket. Writing a provider-format rule well is fiddly in ways that are not obvious until you try it; the trade-offs are the subject of a separate write-up on writing a secret-detection rule for Gitleaks.
Dependency vulnerabilities
Packages are resolved from lockfiles rather than manifests — lockfiles record the version actually installed, which is the version that matters — and looked up in batches against OSV.dev, the open vulnerability database. Five ecosystems are covered: npm, PyPI, Go, crates.io, and RubyGems. No API key is required, and each finding carries the exact version that fixes it, because a vulnerability report without a target version is a research task rather than an action.
Configuration and infrastructure
Thirty-eight pattern-based rules across Dockerfiles (running as root, unpinned :latest base images, secrets passed as build arguments), Compose and Kubernetes manifests (privileged containers, hostPath mounts), Terraform (0.0.0.0/0 ingress, public buckets, unencrypted storage), GitHub Actions workflows (pull_request_target, mutable action references, script injection), and application code (SQL built by string concatenation, shell=True, wildcard CORS, disabled TLS verification, eval and pickle on untrusted input, debug mode left on).
Git history and licences
A secret removed from the working tree is still in the history, and still valid until it is rotated — so the history is scanned separately from the checkout. Alongside that, every dependency's licence is resolved and classified into permissive, file-level copyleft, strong copyleft, and network copyleft, which is the form that question is usually asked in.
Output formats, and why there are several
Findings are emitted as SARIF, HTML, JSON, or Markdown, and the tool also generates a software bill of materials in CycloneDX 1.5 or SPDX 2.3 from the same lockfile parse the vulnerability scan already performed.
The multiple formats are not feature-list padding; each one exists because a different reader needs it. SARIF is the format GitHub code scanning ingests, so emitting it is what puts findings in a pull request rather than in a log nobody opens. JSON is for scripts. Markdown is for a pull-request comment. HTML is for a person who has been sent the report and does not have the tool installed. And the SBOM exists because it is the artifact that gets requested during procurement and diligence review, at which point generating it from a lockfile you have already parsed costs almost nothing.
Exit codes as the actual interface
For a tool intended to run in CI, the exit code matters more than the report. DIRA exits non-zero when findings at or above a configurable severity threshold are present, which is what allows a build to fail on a new critical finding while not failing on a pre-existing low-severity one. Without a threshold, a scanner in CI has exactly two stable states: always green, or turned off.
What it deliberately does not do
Being explicit about limits is part of making the tool usable, and the repository's own README compares DIRA directly against the established alternatives rather than around them. DIRA is pattern-based: it does not perform dataflow or taint analysis, so it cannot tell whether an unsanitised value actually reaches a dangerous call. It covers five dependency ecosystems rather than the fifteen or more that mature scanners handle, and it does not inspect container images or operating-system packages at all. Its configuration ruleset is a fraction of the size of an actively maintained policy engine's.
For anything where those limits matter, purpose-built tools are the right answer, and the README says so by name. What DIRA offers instead is a single zero-dependency command that covers the common cases in one pass and produces a shareable report — which is a genuinely different trade-off, not a claim to be better.
Related reading
The engineering decisions behind DIRA are written up in more depth elsewhere on this site: writing a secret-detection rule and the false-positive trade-offs involved, reproducible builds and SOURCE_DATE_EPOCH, which is the same class of problem as generating a byte-identical SBOM from the same input, and Docker for CS coursework, which covers the container basics several of DIRA's configuration rules are checking for. The other project written up on this site is IntakeKit, and the full list of technical articles is on the writing index.