Releases — LEAPPs
Latest Builds

Tool Releases

Download the latest versions of the LEAPPs forensic tools. All tools are free and open-source.

Visualization · All Platforms

LAVA

LEAPP Artifact Viewer App
……GitHub

What is LAVA?

LAVA lets investigators and analysts browse and explore output reports generated by the *LEAPP family of forensic tools.

Fastest install — macOS via Homebrew
Tapbrew trust leapps-org/leapps; brew tap leapps-org/leapps
GUIbrew install --cask lava
Run the Tap line once. Homebrew 6 will not load a tap outside its own until you trust it, which is what brew trust does. An older Homebrew that has no brew trust command can leave that part out.
On Windows or installing manually? Grab a build below, or see the Homebrew guide.
Live releases · Windows · macOS · Linux
Fetching releases…
View all LAVA releases on GitHub
Android

ALEAPP

Android Logs, Events & Protobuf Parser
……GitHub
Fastest install — macOS via Homebrew
Tapbrew trust leapps-org/leapps; brew tap leapps-org/leapps
Appbrew install --cask aleapp-gui
Run the Tap line once. Homebrew 6 will not load a tap outside its own until you trust it, which is what brew trust does. An older Homebrew that has no brew trust command can leave that part out.
ALEAPP is one program now. The aleapp-gui cask installs ALEAPP.app and links its command line as aleapp: started with no arguments it opens the window, and given arguments it runs as the command line. The separate brew install aleapp formula is deprecated and stays at its last release.
On Windows or installing manually? Grab a build below, or see the Homebrew guide.
Live releases
Fetching releases…
View all ALEAPP releases on GitHub
iOS · iPadOS

iLEAPP

iOS Logs, Events & Plists Parser
……GitHub
Fastest install — macOS via Homebrew
Tapbrew trust leapps-org/leapps; brew tap leapps-org/leapps
Appbrew install --cask ileapp-gui
Run the Tap line once. Homebrew 6 will not load a tap outside its own until you trust it, which is what brew trust does. An older Homebrew that has no brew trust command can leave that part out.
iLEAPP is one program now. The ileapp-gui cask installs iLEAPP.app and links its command line as ileapp: started with no arguments it opens the window, and given arguments it runs as the command line. The separate brew install ileapp formula is deprecated and stays at its last release.
On Windows or installing manually? Grab a build below, or see the Homebrew guide.
Live releases
Fetching releases…
View all iLEAPP releases on GitHub
ISP Returns

RLEAPP

Returns, Logs, Events & Properties Parser
……GitHub
Fastest install — macOS via Homebrew
Tapbrew trust leapps-org/leapps; brew tap leapps-org/leapps
Appbrew install --cask rleapp-gui
Run the Tap line once. Homebrew 6 will not load a tap outside its own until you trust it, which is what brew trust does. An older Homebrew that has no brew trust command can leave that part out.
RLEAPP is one program now. The rleapp-gui cask installs RLEAPP.app and links its command line as rleapp: started with no arguments it opens the window, and given arguments it runs as the command line. The separate brew install rleapp formula is deprecated and stays at its last release.
On Windows or installing manually? Grab a build below, or see the Homebrew guide.
Live releases
Fetching releases…
View all RLEAPP releases on GitHub
Vehicle Systems

VLEAPP

Vehicle Logs, Events & Plists Parser
……GitHub
Fastest install — macOS via Homebrew
Tapbrew trust leapps-org/leapps; brew tap leapps-org/leapps
Appbrew install --cask vleapp-gui
Run the Tap line once. Homebrew 6 will not load a tap outside its own until you trust it, which is what brew trust does. An older Homebrew that has no brew trust command can leave that part out.
VLEAPP is one program now. The vleapp-gui cask installs VLEAPP.app and links its command line as vleapp: started with no arguments it opens the window, and given arguments it runs as the command line. The separate brew install vleapp formula is deprecated and stays at its last release.
On Windows or installing manually? Grab a build below, or see the Homebrew guide.
Live releases
Fetching releases…
View all VLEAPP releases on GitHub
Desktop · Everything Else

DLEAPP

Desktop Logs, Events and Protobuf Parser
……GitHub

What is DLEAPP?

Parse desktop-application artifacts (Electron, Chromium, and friends) — plus any artifact that doesn't fit the platform-specific LEAPPs. If it doesn't belong in iLEAPP, ALEAPP, RLEAPP, or VLEAPP, it belongs here.

Highlights

  • Prebuilt packages for Windows, macOS, and Linux, one program that is both the window and the command line, so no Python is needed
  • Apple Silicon and Intel builds for macOS; x64 and arm64 for Windows and Linux
  • Growing parser set — contributions welcome
Fastest install — macOS via Homebrew
Tapbrew trust leapps-org/leapps; brew tap leapps-org/leapps
Appbrew install --cask dleapp-gui
Run the Tap line once. Homebrew 6 will not load a tap outside its own until you trust it, which is what brew trust does. An older Homebrew that has no brew trust command can leave that part out.
DLEAPP is one program now. The dleapp-gui cask installs DLEAPP.app and links its command line as dleapp: started with no arguments it opens the window, and given arguments it runs as the command line.
On Windows or installing manually? Grab a build below, or see the Homebrew guide.
Live releases
Fetching releases…
View all DLEAPP releases on GitHub
Images · Video

GLEAPP

Graphics, Logs, Examination, Automated Processing, Parsing
……GitHub

What is GLEAPP?

Triage and analysis for large sets of images and video. GLEAPP ingests media from folders, full file system extractions and disk images, hashes and de-duplicates it, reads metadata, pulls video key frames, matches known-hash lists, and opens a local review gallery to work the backlog in.

It is a tool for authorized examiners. It ships no illegal-content hash database, downloads nothing, and performs no content classification: categorizing a file is always the examiner's decision.

Highlights

  • Reads folders, full file system extractions, and E01 or raw disk images, walking each file system file by file, with optional recovery of deleted media
  • Exact and visual de-duplication, EXIF and GPS metadata, video key frames, and known-hash matching (Project VIC, CAID-style, CSV, and the NSRL RDS)
  • HTML contact sheet, CSV, JSON, KMZ, and a LAVA project as output
  • Offline maps: import an area cut by the GLEAPP Map Downloader under Maps, Import, and GLEAPP itself never goes online
  • Builds for Windows, macOS (Apple silicon and Intel), and Linux, so no Python is needed
Fastest install — macOS via Homebrew
Tapbrew trust leapps-org/leapps; brew tap leapps-org/leapps
Appbrew install --cask gleapp
Run the Tap line once. Homebrew 6 will not load a tap outside its own until you trust it, which is what brew trust does. An older Homebrew that has no brew trust command can leave that part out.
The gleapp cask installs GLEAPP.app. It does not link a command line.
On Windows or installing manually? Grab a build below, or see the Homebrew guide.
Live releases
Fetching releases…
View all GLEAPP releases on GitHub
Companion to GLEAPP · Offline maps

GLEAPP Map Downloader

Cut an area of the planet map into one file for GLEAPP's offline maps
……GitHub

What is it?

GLEAPP never goes online, so its maps have to come from somewhere. The Map Downloader is the part that does: run it on a machine with internet access, pick an area and a level of detail, and it saves that area of the Protomaps planet basemap as one .pmtiles file. Copy the file to the offline machine and import it in GLEAPP under Maps, Import. Any viewer that reads PMTiles opens it too.

Privacy: Protomaps' server sees which part of the planet you read, which is the area you ask for. When the area itself is sensitive, cut a larger one around it, or cut it on a machine that is not tied to the case.

Highlights

  • Pick a named region or an exact box, and a detail level from zoom 0 to 15: 10 shows highways and towns, 15 every street and building. Check the size first, then download
  • Downloads only the tiles inside the area, read from the planet file with HTTP range requests, and an area too large for one file is refused before anything is downloaded
  • A stopped or failed download leaves no file that looks whole
  • The map data is OpenStreetMap's, under the Open Database License. The file carries the © OpenStreetMap credit, and a map shown anywhere else must credit it too. Not affiliated with Protomaps or the OpenStreetMap Foundation
  • One Python file, standard library only, with a window and a command line. Executables for Windows, macOS and Linux (x64 and arm64). Since v0.2.0 the macOS build is an app in a disk image, signed with a Developer ID and notarized by Apple; the Windows and Linux builds are not code signed
Live releases
Fetching releases…
View all GLEAPP Map Downloader releases on GitHub
Automation · macOS · Windows

Batch LEAPP

Run any LEAPP tool across a folder of extractions
……GitHub

What is Batch LEAPP?

Point it at a directory and it finds every extraction inside, runs iLEAPP, ALEAPP, RLEAPP, or VLEAPP against each one in parallel, and builds a single report index linking every result — with SHA-256 hashing and a manifest for your case file.

Highlights

  • One index.html linking every report and LAVA project
  • SHA-256 manifest (CSV & JSON) for casework
  • GUI and CLI — prebuilt for macOS and Windows
  • Read the announcement post
Live releases
Fetching releases…
View all Batch LEAPP releases on GitHub
Windows builds

Code signing policy

How the Windows builds of the LEAPPs are signed

Status

The Windows builds are not signed yet. We are applying to SignPath Foundation's free code signing program for open source projects, and this policy applies to every Windows release of iLEAPP, ALEAPP, RLEAPP, VLEAPP, DLEAPP and GLEAPP signed under it.

Free code signing provided by SignPath.io, certificate by SignPath Foundation.

Signed builds will be made from source by GitHub Actions in each tool's own repository, and each release will be signed only after an approver confirms it.

SignPath signs each tool's single-file program, the one executable in its portable zip. Third-party files packed inside it, such as Mandiant's Unified Log parser in iLEAPP and DLEAPP, are not signed on their own.

Team roles

Privacy

This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it.

'; return; } const shown = releases; function buildCard(r, i) { const assets = (r.assets || []).filter(a => !a.name.includes('.blockmap') && !a.name.includes('latest')); // One asset button. label=null renders the raw filename (older // releases / unparseable assets); otherwise the friendly label with // the filename in the tooltip. Copy-URL and SHA-256 buttons always kept. function assetBtn(a, ai, label, primary) { const dlCount = a.download_count > 0 ? `${formatStars(a.download_count)}` : ''; const copyId = `copy-${id}-${i}-${ai}`; const hashId = `hash-${id}-${i}-${ai}`; const digest = a.digest ? a.digest.replace(/^sha256:/, '') : ''; const hashBtn = digest ? `` : ''; const text = label || `${getOSIcon(a.name)} ${a.name}`; return `
${text} ${a.size ? '' + formatBytes(a.size) + '' : ''} ${dlCount}${hashBtn}
`; } let assetBtns = ''; const parsed = assets.map((a, ai) => { const p = parseAsset(a.name); if (!p.flavor && tool.flavor) { p.flavor = tool.flavor; p.gui = tool.flavor.startsWith('GUI'); } return { a, ai, p }; }); const groupable = i === 0 && parsed.filter(x => x.p.os).length >= 3; if (groupable) { // Latest release: group by OS, visitor's platform first, GUI before // CLI inside each row, GUI on the visitor's row styled primary. const OS_META = { windows: ['ti-brand-windows', 'Windows'], macos: ['ti-brand-apple', 'macOS'], linux: ['ti-brand-ubuntu', 'Linux'] }; const order = ['windows', 'macos', 'linux'].sort((x, y) => (y === VISITOR_OS) - (x === VISITOR_OS)); const hasFlavor = parsed.some(x => x.p.flavor); const rows = order.map(os => { const inRow = parsed.filter(x => x.p.os === os) .sort((x, y) => (y.p.gui - x.p.gui) || String(x.p.arch).localeCompare(String(y.p.arch)) || String(x.p.kind).localeCompare(String(y.p.kind))); if (!inRow.length) return ''; // If two assets in a row would get the same label (e.g. a .zip and // a .tar.gz of the same build), append the file format. An // installer or portable build says so instead. const keyOf = x => `${x.p.flavor}|${x.p.arch}|${x.p.kind}`; const dupes = new Set(inRow.map(keyOf).filter((k, idx, arr) => arr.indexOf(k) !== idx)); const extOf = n => n.toLowerCase().endsWith('.tar.gz') ? 'tar.gz' : n.split('.').pop().toLowerCase(); const btns = inRow.map(x => { const flavor = hasFlavor ? (x.p.flavor || 'CLI') : ''; const ext = x.p.kind ? ` · ${x.p.kind}` : (dupes.has(keyOf(x)) ? ` · ${extOf(x.a.name)}` : ''); const label = `${flavor ? `${flavor} · ` : ''}${x.p.arch || 'download'}${ext}`; return assetBtn(x.a, x.ai, label, os === VISITOR_OS && (x.p.gui || !hasFlavor)); }).join(''); const yourOS = os === VISITOR_OS ? ' your system' : ''; return `
${OS_META[os][1]}${yourOS}
${btns}
`; }).join(''); const leftover = parsed.filter(x => !x.p.os); const leftoverHtml = leftover.length ? `
Other
${leftover.map(x => assetBtn(x.a, x.ai, null, false)).join('')}
` : ''; assetBtns = `
${rows}${leftoverHtml}
`; } else { assetBtns = parsed.map((x, k) => assetBtn(x.a, x.ai, null, k === 0)).join(''); } const body = truncateBody(r.body); const releaseDlCount = assets.reduce((sum, a) => sum + (a.download_count || 0), 0); const releaseDlStr = releaseDlCount > 0 ? `${formatStars(releaseDlCount)}` : ''; const releaseUrl = `https://github.com/${tool.repo}/releases/tag/${r.tag_name}`; const shareText = encodeURIComponent(`${tool.name} ${r.tag_name} just released! Download the latest forensics tools from LEAPPs. ${releaseUrl}`); const linkedinUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(releaseUrl)}`; const shareBtnId = `share-${id}-${i}`; return `
${r.tag_name} ${i === 0 ? 'Latest' : ''} ${releaseDlStr}
${formatDate(r.published_at)}
${body ? `
${body}
` : ''} ${assetBtns ? `
${assetBtns}
` : ''}
`; } const latest = buildCard(shown[0], 0); const older = shown.slice(1); let olderHTML = ''; if (older.length > 0) { const cards = older.map((r, i) => buildCard(r, i + 1)).join(''); olderHTML = `
${older.length} older release${older.length > 1 ? 's' : ''}
${cards}
`; } container.innerHTML = latest + olderHTML; } async function fetchReleases(tool) { const container = document.getElementById('releases-' + tool.id); try { const res = await fetch(`https://leapps-api.4n6-198.workers.dev/repos/${tool.repo}/releases?per_page=100`); if (!res.ok) throw new Error('HTTP ' + res.status); const data = (await res.json()).filter(r => !r.draft); renderReleases(tool.id, data, tool); } catch (e) { container.innerHTML = `
Could not load releases. View on GitHub →
`; } } Promise.all(tools.map(fetchReleases)).then(() => { if (window.location.hash) { const target = document.querySelector(window.location.hash); if (target) { setTimeout(() => target.scrollIntoView({ behavior: 'smooth' }), 100); } } }); // Copy-to-clipboard for the Homebrew install commands document.querySelectorAll('.lp-brew-copy').forEach(btn => { btn.addEventListener('click', async () => { const cmd = btn.getAttribute('data-copy'); try { await navigator.clipboard.writeText(cmd); } catch (e) { const ta = document.createElement('textarea'); ta.value = cmd; document.body.appendChild(ta); ta.select(); try { document.execCommand('copy'); } catch (_) {} ta.remove(); } const icon = btn.querySelector('i'); btn.classList.add('copied'); if (icon) icon.className = 'ti ti-check'; setTimeout(() => { btn.classList.remove('copied'); if (icon) icon.className = 'ti ti-copy'; }, 1500); if (window.gtag) { window.gtag('event', 'install_copy', { tool: btn.getAttribute('data-tool') || '', link_text: cmd.slice(0, 100) }); } }); }); // Mobile hamburger menu const hamburger = document.getElementById('lp-hamburger'); const mobileMenu = document.getElementById('lp-mobile-menu'); hamburger.addEventListener('click', function() { hamburger.classList.toggle('open'); mobileMenu.classList.toggle('open'); }); function closeMobileMenu() { hamburger.classList.remove('open'); mobileMenu.classList.remove('open'); } document.addEventListener('click', function(e) { if (!hamburger.contains(e.target) && !mobileMenu.contains(e.target)) { closeMobileMenu(); } }); // Fetch star counts function formatStars(n) { if (n >= 1000) return (n / 1000).toFixed(1).replace(/\.0$/, '') + 'k'; return n.toString(); } async function fetchStars(tool) { const el = document.getElementById('stars-releases-' + tool.id); if (!el) return; try { const res = await fetch(`https://leapps-api.4n6-198.workers.dev/repos/${tool.repo}`); if (!res.ok) throw new Error('HTTP ' + res.status); const data = await res.json(); el.innerHTML = `${formatStars(data.stargazers_count)}`; el.classList.remove('loading'); } catch(e) { el.style.display = 'none'; } } async function fetchTotalDownloads(tool) { const el = document.getElementById('dlcount-releases-' + tool.id); if (!el) return; try { const res = await fetch(`https://leapps-api.4n6-198.workers.dev/repos/${tool.repo}/releases?per_page=100`); if (!res.ok) throw new Error('HTTP ' + res.status); const releases = (await res.json()).filter(r => !r.draft); const total = releases.reduce((sum, r) => { return sum + (r.assets || []).reduce((s, a) => s + (a.download_count || 0), 0); }, 0); if (total > 0) { el.innerHTML = `${formatStars(total)} downloads`; el.classList.remove('loading'); } else { el.style.display = 'none'; } } catch(e) { el.style.display = 'none'; } } // Copy release URL to clipboard function copyReleaseUrl(url, btnId) { navigator.clipboard.writeText(url).then(function() { const btn = document.getElementById(btnId); if (!btn) return; btn.classList.add('copied'); btn.innerHTML = ''; setTimeout(function() { btn.classList.remove('copied'); btn.innerHTML = ''; }, 2000); }).catch(function() { const ta = document.createElement('textarea'); ta.value = url; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); const btn = document.getElementById(btnId); if (btn) { btn.classList.add('copied'); btn.innerHTML = ''; setTimeout(function() { btn.classList.remove('copied'); btn.innerHTML = ''; }, 2000); } }); } // Copy SHA to clipboard function copySha(sha, btnId) { navigator.clipboard.writeText(sha).then(function() { const btn = document.getElementById(btnId); if (!btn) return; const icon = btn.querySelector('i'); btn.classList.add('copied'); icon.className = 'ti ti-check'; setTimeout(function() { btn.classList.remove('copied'); icon.className = 'ti ti-fingerprint'; }, 2000); }).catch(function() { const ta = document.createElement('textarea'); ta.value = sha; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); const btn = document.getElementById(btnId); if (btn) { const icon = btn.querySelector('i'); btn.classList.add('copied'); icon.className = 'ti ti-check'; setTimeout(function() { btn.classList.remove('copied'); icon.className = 'ti ti-fingerprint'; }, 2000); } }); } // Copy URL to clipboard function copyUrl(url, btnId) { navigator.clipboard.writeText(url).then(function() { const btn = document.getElementById(btnId); if (!btn) return; const icon = btn.querySelector('i'); btn.classList.add('copied'); icon.className = 'ti ti-check'; setTimeout(function() { btn.classList.remove('copied'); icon.className = 'ti ti-clipboard'; }, 2000); }).catch(function() { const ta = document.createElement('textarea'); ta.value = url; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); const btn = document.getElementById(btnId); if (btn) { const icon = btn.querySelector('i'); btn.classList.add('copied'); icon.className = 'ti ti-check'; setTimeout(function() { btn.classList.remove('copied'); icon.className = 'ti ti-clipboard'; }, 2000); } }); } tools.forEach(fetchStars); tools.forEach(fetchTotalDownloads); // Set print date on page header window.addEventListener('beforeprint', function() { const inner = document.querySelector('.lp-page-header-inner'); if (inner) inner.setAttribute('data-print-date', new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })); });