MITHRIL(1)
π mithril(1) π
okay bestie, this is the manual page for mithril β she lives in your terminal and she's literally so good at firmware forensics. grab a boba, we're going in π§
β¨ NAME β¨
mithril β analyze firmware contents for secrets, SBOM, CVEs, and licenses π
β¨ SYNOPSIS β¨
mithril [options] <file|dir>
mithril --fetch-db|--update-db [--with-kernel-feed]
β¨ DESCRIPTION β¨
so the way that mithril works is she reads the contents of firmware and IoT software β either a single file or an unpacked rootfs β and then reports four things as structured findings. not me being obsessed with structured output π
- secrets: embedded credential and key material (API tokens, cloud keys, JWTs, private keys,
/etc/shadowhashes), and each one comes with a deterministic offline confidence rating. no vibes-based guessing here, it's giving rigor β¨ - SBOM: a software bill of materials built from package databases (
dpkg/opkg/apk/rpm), language manifests, ELF version strings, versioned libc filenames, and the kernel banner. emitted as CycloneDX and SPDX π - CVEs: the SBOM joined against a local offline vulnerability mirror (OSV plus NVD/CPE) and a curated, version- and kconfig-gated kernel-CVE checklist, annotated with CISA KEV and EPSS. yes queen, all of that π₯
- licenses: the open-source licenses present, for compliance and provenance π
mithril pairs with moria(1), which handles structural identification and unpacking. a typical pipeline runs moria -e to unpack an image, then mithril over the extracted tree. ship it π«Ά
a scan makes no network calls. the secrets, SBOM, and license passes are fully offline. the CVE pass reads a local mirror that is refreshed out of band (see THE CVE MIRROR below), so it is air-gappable once the mirror is in place. output is human-readable by default; pass -j/--json for a single JSON object designed to be consumed by a tool or model π€
with no pass flag, every pass runs. naming one or more passes (--secrets, --sbom, --cve, --licenses, --boot, --keys) restricts the run to just those. main character energy: you pick who gets to show up π
πΈ ARGUMENTS πΈ
<file|dir>β a single file, or a directory (typicallymoria's.extracted/output) to scan recursively π¦
β¨ OPTIONS β¨
π Passes
--secretsβ scan file content for credential and key material π--sbomβ inventory software components and their versions π¦--cveβ match the detected components against known vulnerabilities in the local mirror. needs the mirror (see--fetch-db) π--licensesβ identify open-source licenses π--bootβ boot-security intel: U-Boot environment, device tree, and FIT/AVB/UEFI verified-boot posture π₯Ύ--keysβ public-key weakness. this one is so much: keys whose private half is public (hardcoded/default keys, the compromised eMudhra intermediate CAs), the ROCA fingerprint (CVE-2017-15361), undersized or broken RSA keys, RSA factoring recoveries (Fermat/batch-GCD/Wiener), and near-zero EC private scalars recovered by a bounded search (the Oct 2026 eMudhra P-384 compromise). literally the whole key drama ποΈ-A,--allβ run every pass. this is the default when no pass is named π
π Output detail
-j,--jsonβ emit a single JSON object instead of the human-readable view. JSON always carries the complete result set, so the detail options below only affect the human view. use this when a tool or model will parse the output π€-v,--verboseβ human view: show full values instead of tail-truncating long ones with"..."π--license-pathsβ list the file locations of each license, not just a count (human output). implies--licensesπ--component-cves-fullβ human view: list every component CVE, not just the high-signal set (on CISA KEV, or CVSS9.0and above, or EPSS0.10and above). implies--cveπ¨--kernel-cves-fullβ list every CVE for the detected kernel version, matched branch-aware, instead of the curated high-signal checklist. needs the kernel feed (see--with-kernel-feed). implies--cveπ§--fullβ maximum human detail in one switch: equivalent to--verbose,--license-paths,--component-cves-full, and--kernel-cves-fulltogether. no effect on JSON, which is always complete. one button, everything, slay β¨--dump-kconfigβ print the recovered kernel.configto stdout, then exit π¨οΈ
π¦ CVE mirror
--fetch-dbβ download a prebuilt CVE mirror and verify it against a published SHA-256, then exit. needscurl. this is the networked first-run step; see THE CVE MIRROR below π--update-dbβ rebuild the local CVE mirror from the upstream feeds, then exit. slower than--fetch-db; needscurlandunzipπ’--with-kernel-feedβ given with--fetch-dbor--update-db, also fetch the optional full kernel.org (Linux CNA) CVE feed that backs--kernel-cves-fullπ§--no-fetchβ suppress the interactive offer to download the CVE mirror. when the--cvepass runs with no local mirror on an interactive terminal,mithrilotherwise asks whether to fetch it. with--no-fetch(or the environment variableMITHRIL_NO_FETCH), it never asks: a missing mirror is reported as an error and the scan exits nonzero, as in a non-interactive run. use it in scripts and CI π
π Configuration
--rules FILEβ add user-defined detection rules from a JSON file π-C,--outdir DIRβ also write the report toDIR, regardless of the stdout format:mithril-report.json(the complete JSON result set) and, when the SBOM pass runs,sbom.cdx.jsonandsbom.spdx.json(the CycloneDX and SPDX bills of materials). these standard-format SBOMs are produced only through-C. β οΈ note thatmoria(1)also has a-Cbut means its extraction output directory; here it is the report output directory. don't mix them up bestie, iykyk π--threads Nβ worker threads for tree scans. default: automatic β‘
β Information
-h,--helpβ print help and exit π«Ά--versionβ print version and exit π·οΈ
π THE CVE MIRROR π
the --cve pass reads a local mirror under ~/.local/share/mithril (or $MITHRIL_DB) β a compact memory-mapped index built from OSV.dev, the NVD 2.0 API, the CISA KEV catalog, and FIRST's EPSS scores β¨
on a first run, populate it once with mithril --fetch-db before the first CVE scan. without it, --cve reports the missing database and exits nonzero π
only --fetch-db and --update-db ever touch the network; a normal scan does not. no cap, that's the whole point π
π EXIT STATUS π
0β success π1β runtime error (for example, an unreadable target or a missing CVE mirror for--cve) π¬2β usage error (unknown option, missing argument) π
π§ ENVIRONMENT π§
MITHRIL_DBβ path to the local CVE mirror (overrides the default under~/.local/share/mithril)MITHRIL_DB_URLβ base URL that--fetch-dbdownloads the prebuilt mirror fromNVD_API_KEYβ optional NVD API key used by--update-dbto raise the upstream rate limit. it works without one, just more slowly πXDG_DATA_HOMEβ if set,mithrillocates the mirror under$XDG_DATA_HOME/mithrilinstead of~/.local/share/mithrilNO_COLORβ disables bold section headers in--helpoutput π¨
πΈ FILES πΈ
~/.local/share/mithril/β default location of the local CVE mirror (OSV plus NVD/CPE index, KEV, EPSS, and the optional kernel feed) π
π₯ EXAMPLES π₯
run every analysis on an unpacked tree:
mithril ./rootfs/
only the secrets pass:
mithril --secrets ./rootfs/
JSON output for a tool or model:
mithril -j ./rootfs/
first run: download the CVE mirror:
mithril --fetch-db
the full pipeline with moria:
moria -e firmware.bin && mithril firmware.bin.extracted/
π SEE ALSO π
full documentation: README.md and docs/ in the source tree (https://github.com/nmatt0/mithril) π
and that's the whole page, bestie π«Ά this is mithril version 0.4.0, dated 2026-10-22 β go forth, scan some firmware, and stay iconic π
β¨
π¦ where this page comes from
- nixpkgs unstable: mithril 0.4.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms