5 min read

whisper.cpp: Fast, Private Speech to Text (GitHub, Scanned)

OpenAI's Whisper speech recognition in plain C/C++: fast on a laptop, fully offline, no Python.

whisper.cpp logo
✅
Scan: safe. Nothing to warn about. The engine has no package dependencies to speak of; every advisory sits in a Node.js example's test tooling, and the committed model files are empty test fixtures. Scanned Sep 24, 2026; the full report is below.

whisper.cpp runs OpenAI's Whisper speech recognition models without Python or PyTorch. It is plain C and C++ on the same ggml library that powers llama.cpp, so it gets the same treatment: Metal on Apple Silicon, CUDA, Vulkan, ROCm, Core ML for the Neural Engine, and integer quantization that shrinks a model to a fraction of its size. The whisper-cli tool transcribes a file, whisper-stream transcribes the microphone live, and whisper-server exposes an OpenAI-style HTTP transcription API.

It earns its place for being the transcription engine inside a long list of desktop dictation and captioning apps, and for running where the Python original will not: iPhones, Android, a Raspberry Pi, a browser tab through WebAssembly. It started as Georgi Gerganov's port and now lives under ggml-org with more than 1,000 contributors. MIT-licensed, like the Whisper models themselves.

Who it is for

Anyone who wants transcripts or subtitles without uploading audio, developers embedding speech recognition in an app or device, and people for whom the Python Whisper is too slow or too heavy to install.

Getting started

1. Clone the repository

git clone https://github.com/ggml-org/whisper.cpp.git && cd whisper.cpp

2. Download a model converted to ggml format

sh ./models/download-ggml-model.sh base.en

3. Build, then transcribe the bundled sample

cmake -B build && cmake --build build -j --config Release && ./build/bin/whisper-cli -f samples/jfk.wav

whisper-cli reads 16-bit WAV. Convert anything else first, as the README shows: ffmpeg -i input.mp3 -ar 16000 -ac 1 -c:a pcm_s16le output.wav. The download script fetches weights from the project's Hugging Face repository.

Safety scan

We cloned ggml-org/whisper.cpp at commit d09f61a on Sep 24, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.

  • No secrets, no pattern hits and no bare-IP URLs across about 525,000 lines of C, C++, CUDA and Metal.
  • The three scripts listed as installers are ci/run.sh, the CI test driver; a 24-line launcher inside an experimental ggml back end; and scripts/deploy-wasm.sh, which publishes the WebAssembly demos. None uses sudo, edits a shell profile or pipes a download to a shell.
  • 15 committed binaries. Twelve are model files prefixed for-tests- (14 KB to 885 KB), which the models README describes as containing no weights and existing for the CI's sanitizer tests. The other three are Gradle wrapper jars for the Java binding and the Android examples.
  • All 62 known advisories (2 critical, 33 high) are in examples/addon.node/package-lock.json, the Node.js addon example, whose only dependencies are the dev tools cmake-js, Jest and node-addon-api. The Go binding's seven packages have none, and the C/C++ library vendors what little it uses.
  • 22 workflows, none using pull_request_target; 16 of 41 third-party actions are pinned to a commit. Licence and contributing guide present; unlike llama.cpp there is no security policy, and no Dependabot or CodeQL.

What the scanner counted

CheckResult
SecretsNone found.
Suspicious codeNone found.
Install-time code3 installer scripts
Committed binaries15 executable or compiled objects committed; listed under the raw findings.
CI workflows22 workflows. None use pull_request_target. 25 of 41 third-party actions pinned to a tag rather than a commit.
Network hosts40 distinct hosts referenced from source; most often json.nlohmann.me, github.com, huggingface.co, nlohmann.me. No URLs to bare IP addresses.
Known vulnerabilities62 advisories across 328 pinned packages: 2 critical, 33 high, 24 moderate, 3 low. bindings/go/go.mod: 7 packages, 0 advisories; examples/addon.node/package-lock.json: 326 packages, 62 advisories.
Project hygieneHas licence file, contributing guide. Missing security policy, automated dependency updates, CodeQL.
OpenSSF ScorecardNot scored: the project is not in Scorecard's weekly index.

The raw findings

Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.

Installer scripts (3)
Committed binaries (15)
  • models/for-tests-silero-v6.2.0-ggml.bin: .bin, 885 KB
  • models/for-tests-ggml-base.en.bin: .bin, 587 KB
  • models/for-tests-ggml-medium.en.bin: .bin, 587 KB
  • models/for-tests-ggml-small.en.bin: .bin, 587 KB
  • models/for-tests-ggml-tiny.en.bin: .bin, 587 KB
  • models/for-tests-ggml-base.bin: .bin, 575 KB
  • models/for-tests-ggml-large.bin: .bin, 575 KB
  • models/for-tests-ggml-medium.bin: .bin, 575 KB
  • models/for-tests-ggml-small.bin: .bin, 575 KB
  • models/for-tests-ggml-tiny.bin: .bin, 575 KB
  • bindings/java/gradle/wrapper/gradle-wrapper.jar: JAR, 62 KB
  • examples/whisper.android/gradle/wrapper/gradle-wrapper.jar: JAR, 59 KB
  • examples/whisper.android.java/gradle/wrapper/gradle-wrapper.jar: JAR, 54 KB
  • models/for-tests-ggml-parakeet-tdt.bin: .bin, 17 KB
  • models/for-tests-ggml-parakeet-tdt-bad-nfft0.bin: .bin, 14 KB
Worst known vulnerabilities (24 of 62)
AdvisorySeverityPackageSummary
GHSA-fjxv-7rqg-78g4criticalform-data@4.0.2form-data uses unsafe random function in form-data for choosing boundary
GHSA-23hp-3jrh-7fpwcriticaltar@6.2.1node-tar: Decompression/parse DoS via unlimited input
GHSA-35jp-ww65-95whhighaxios@1.8.4axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `config.proxy`
GHSA-3g43-6gmg-66jwhighaxios@1.8.4axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollution Gadget in Config Merge
GHSA-43fc-jf86-j433highaxios@1.8.4Axios is Vulnerable to Denial of Service via __proto__ Key in mergeConfig
GHSA-4hjh-wcwx-xvwjhighaxios@1.8.4Axios is vulnerable to DoS attack through lack of data size check
GHSA-6chq-wfr3-2hj9highaxios@1.8.4Axios: Header Injection via Prototype Pollution
GHSA-777c-7fjr-54vfhighaxios@1.8.4Allocation of Resources Without Limits or Throttling in Axios
GHSA-hfxv-24rg-xrqfhighaxios@1.8.4Axios: Regular Expression Denial of Service (ReDoS) via Cookie Name Injection
GHSA-j5f8-grm9-p9fchighaxios@1.8.4Axios: Proxy-Authorization header leaks to redirect target when proxy is re-evaluated to direct connection
GHSA-p92q-9vqr-4j8vhighaxios@1.8.4Axios: Proxy-Authorization Credential Leak to Origin Server Across HTTP-to-HTTPS Redirect in Axios Node.js HTTP Adapter
GHSA-pf86-5x62-jrwfhighaxios@1.8.4Axios: Prototype Pollution Gadgets - Response Tampering, Data Exfiltration, and Request Hijacking
GHSA-pmwg-cvhr-8vh7highaxios@1.8.4Axios: Incomplete Fix for CVE-2025-62718 - NO_PROXY Protection Bypassed via RFC 1122 Loopback Subnet (127.0.0.0/8) in Ax…
GHSA-q8qp-cvcw-x6jjhighaxios@1.8.4Axios has prototype pollution read-side gadgets in HTTP adapter that allow credential injection and request hijacking
GHSA-3jxr-9vmj-r5cphighbrace-expansion@1.1.11brace-expansion: DoS via exponential-time expansion of consecutive non-expanding {} groups
GHSA-mh99-v99m-4gvghighbrace-expansion@1.1.11brace-expansion: DoS via unbounded expansion length causing an out-of-memory process crash
GHSA-rgw5-rvv9-x895highbrace-expansion@1.1.11brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-14257 mitigation
GHSA-73wf-gq98-2v4ghighbrowserslist@4.24.4Browserslist: Uncaught crash / prototype write via untrusted browserslist-stats.json custom stats (normalizeStats)
GHSA-c83g-rgw3-j3cxhighbrowserslist@4.24.4Browserslist: Unbounded memory growth (no cache eviction) via distinct query results, leading to eventual OOM
GHSA-hmw2-7cc7-3qxxhighform-data@4.0.2form-data: CRLF injection in form-data via unescaped multipart field names and filenames
GHSA-2883-xcg3-v3hhhighjs-yaml@3.14.1js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources
GHSA-52cp-r559-cp3mhighjs-yaml@3.14.1js-yaml: YAML merge-key chains can force quadratic CPU consumption
GHSA-5p4m-2wfm-xmqjhighjs-yaml@3.14.1JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) - CVE-2026-59870 fix not backported
GHSA-23c5-xmqv-rm74highminimatch@3.1.2minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regular expressions

By the numbers

Stars53.9K
Forks6,195
Contributors1,042
Commits5,311
Open issues170
Open pull requests175
Releases43
Latest releasev1.9.4
LicenceMIT
Main languageC++
Project age4 years
Last pushSep 24, 2026
Tracked files2,001
Lines of code525.4K
Checkout size39 MB

Lines by language: C++ 240.5K, C/C++ header 100K, C 92.5K, CUDA 26.4K, Metal 12.3K, GLSL 7,984.

Questions

Is whisper.cpp free?

Yes. whisper.cpp is MIT-licensed and free for any use, including commercial products, and the Whisper models it runs were released by OpenAI under MIT as well. There is no paid tier and no account. The converted models download from the project's Hugging Face repository, also free.

What is the difference between whisper.cpp and OpenAI Whisper?

They run the same models. OpenAI's repository is the Python reference implementation on PyTorch, convenient in notebooks and research code. whisper.cpp is a rewrite in C/C++ with no Python, quantized models and hardware back ends, so it starts instantly, uses less memory and is usually much faster on CPUs and Apple Silicon. Accuracy is essentially the same for the same model size.

What hardware does whisper.cpp need?

Less than you would expect. By the README's table the tiny model needs about 273 MB of memory, base about 388 MB, medium about 2.1 GB and large about 3.9 GB. It runs on a CPU alone, including a Raspberry Pi; a GPU or Apple Silicon makes the large models fast enough for real-time work.


This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.