npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

binary-sentinel

v1.1.0

Published

Static PE/ELF/Mach-O triage in pure JS: headers, sections, entropy, imports, imphash, Rich header, overlays, TLS callbacks, packer hints (UPX, ASPack, VMProtect...), suspicious API capabilities mapped to ATT&CK, and hardening (ASLR, NX, CFG, PIE, RELRO, c

Readme

binary-sentinel

npm version CI Node License: MIT

Static PE and ELF triage in pure JavaScript: headers, sections, entropy, imports, imphash, packer hints, capabilities and hardening checks.

binary-sentinel gives an analyst a quick first look at a Windows PE (EXE/DLL/SYS, 32- and 64-bit) or Linux/Unix ELF file without leaving the terminal or CI. The same parser can also check your own release binaries for missing hardening (ASLR, DEP/NX, CFG, PIE, RELRO, stack canaries). Samples are only ever read as bytes and are never executed or loaded.

CLI, library and GitHub Action. Node.js 18+, zero runtime dependencies, no native code.

What it extracts

PE: machine, bitness, subsystem, compile timestamp, entry point and its section, image base, DLL characteristics (ASLR, high-entropy VA, DEP, CFG, NO_SEH, AppContainer), data directories, sections (name, sizes, RWX flags, Shannon entropy, MD5), imports (including delay-load imports and ordinals), imphash (same algorithm as pefile, verified against it), exports, TLS callbacks, Rich header (entries + hash), overlay (offset, size, entropy, embedded file type), Authenticode presence, .NET (CLR) detection and the header checksum (recomputed).

ELF: class, endianness, OS ABI, type, machine, entry point, program headers (with RWX), sections and their entropy, interpreter, DT_NEEDED libraries, SONAME, RPATH/RUNPATH, dynamic imports/exports, an import hash (MD5 of sorted imported symbols), stripped state, and checksec-style hardening: PIE, NX, RELRO (none/partial/full), BIND_NOW, stack canary and FORTIFY_SOURCE.

Every file also gets its MD5/SHA1/SHA256/SHA512, overall entropy and a magic-byte type (also recognises Mach-O, ZIP, PDF, OLE, LNK, RAR, 7z, CAB, ISO, scripts…).

Mach-O, Authenticode and capability rules

binary-sentinel ./MyApp.app/Contents/MacOS/MyApp      # Mach-O (thin or universal)
binary-sentinel setup.exe                             # verifies the Authenticode signature
binary-sentinel ./samples --rules ./my-capa-rules/    # capa-style YAML rules

Capability rules use a subset of the capa rule format: api, import, export, string (exact or /regex/i), substring, section, format, os, arch, match and characteristic: embedded pe, combined with and, or, not, optional and N or more. All scopes are evaluated at file level; features that need disassembly (bytes, number, mnemonic, offset) never match. Set meta.severity to choose the finding severity.

Authenticode verification checks the image hash, the signed digest and the signer's signature (including nested signatures). It does not consult an OS trust store: a valid signature from a certificate chain you don't trust is still reported as valid, with the chain listed in JSON output (--details).

import { analyzeBuffer, verifyAuthenticode, parseMachO, loadRules } from 'binary-sentinel';
const { info, raw, summary } = analyzeBuffer(buf, 'file.exe', { rules: loadRules('./rules') });

Module formats and types

Ships ESM and CommonJS (import and require both work, via exports), with TypeScript declarations generated from the source at build time. Tests run on Node 18/20/22 in GitHub Actions (test/), including require/import checks against the packed tarball; releases are published with npm provenance.

Rules

| Rule | Default | What it means | |---|---|---| | packer-section | high | Section names of UPX, ASPack, PECompact, MPRESS, NsPack, Themida/WinLicense, VMProtect, Enigma, Petite, FSG, MEW, Obsidium and more | | packer-signature | high | Packer/protector strings (UPX!, PECompact2, ConfuserEx…) | | rwx-section | high | Writable + executable section or LOAD segment | | entrypoint-anomaly | high | Entry point outside every section, in a non-executable section or in the last section | | embedded-executable | high | Overlay contains another PE/ELF or archive (droppers, installers) | | injection-imports | high | Classic injection API combinations (VirtualAllocEx + WriteProcessMemory + CreateRemoteThread, process hollowing…) | | high-entropy-section | medium | Executable section ≥ 7.2 bits/byte, or any section ≥ 7.6 | | dynamic-api-resolution | medium | Fewer than 15 imports including GetProcAddress/dlsym | | virtual-only-section | medium | Executable section with no raw data but a large virtual size | | tls-callbacks | medium | Code that runs before the entry point | | suspicious-imports | medium | Capability groups mapped to ATT&CK: injection (T1055), keylogging (T1056.001), screen capture (T1113), credential access (T1003), downloads (T1105), registry/service persistence (T1547.001/T1543.003), token manipulation (T1134), anti-debugging (T1622), clipboard (T1115), log clearing (T1070.001) | | header-anomaly | medium | Truncated or malformed headers, imports outside the file, no ELF section table | | unsafe-rpath | medium | RPATH/RUNPATH that is relative or in /tmp, /var/tmp, /dev/shm | | overlay | low (medium if high-entropy) | Data after the last section | | timestamp-anomaly, checksum-mismatch | low | Forged/zero/future timestamps; file modified after linking | | no-aslr, no-nx, no-relro | low | Missing hardening (high in --profile hardening) | | signature-invalid, masquerading | high | Authenticode does not verify; vendor version info without a valid signature | | embedded-executable | high | Overlay or PE resource that is itself an executable | | signature-untrusted, high-entropy-resource, dylib-hijack-risk, capability-rule | medium | Self-signed signer; encrypted resource payload; weak @rpath dylib; custom rule match (severity from meta.severity) | | signature-expired, version-info-mismatch | low | Expired signer without timestamp; renamed binary | | no-cfg, no-canary, unsigned, adhoc-signed, encrypted-binary, dotnet, unsupported-format | info | Context (unsupported-format = DOS MZ only) |

Network, process, discovery, crypto and memory APIs are listed as capabilities in the summary but do not raise findings on their own, because almost every program uses them. IsDebuggerPresent on its own is ignored because the MSVC CRT imports it.

Profiles

  • --profile triage (default): for malware triage and incoming-file screening.
  • --profile hardening: for your own build artefacts. Missing ASLR/NX/RPATH safety becomes high, RELRO/canary medium, and capability findings drop to info.

Install and run

npx binary-sentinel suspicious.exe
npx binary-sentinel ./samples --format json --json triage.json   # JSON includes full headers/sections/imports
npx binary-sentinel dist/ --profile hardening --fail-on high      # CI gate for your own binaries

Library

import { parsePE, parseELF, triage, capabilities, entropy } from 'binary-sentinel';
import { readFileSync } from 'node:fs';

const pe = parsePE(readFileSync('sample.exe'));
pe.imphash; pe.sections.map((s) => [s.name, s.entropy]); pe.tlsCallbacks; pe.overlay;

const report = triage(['samples/'], { profile: 'triage' });

Configuration

Put a .binary-sentinel.json in the working directory (or pass --config <file>). Every key is optional; CLI flags override the file.

{
  "failOn": "high",
  "severity": { "packer-section": "high" },
  "allow": [
    { "rule": "packer-section", "match": "*vendor-installer.exe", "reason": "Accepted risk, ticket SEC-123", "expires": "2027-03-31" }
  ]
}
  • severity changes the severity of any rule, or turns it off.
  • allow suppresses findings. Each entry needs a rule (globs such as packer-* work) and a reason, and can be narrowed with target and match (a glob tested against the target, location and value). Suppressed findings are listed in the JSON report. When expires (YYYY-MM-DD) has passed, the finding comes back together with an allow-expired finding, so exceptions can't be forgotten. Entries that match nothing are reported as allow-unused (info).

Output and exit codes

  • --format text|json|sarif|markdown for stdout, plus --json, --sarif and --markdown <file> to write extra copies in one run. SARIF 2.1.0 works with GitHub code scanning.
  • --fail-on critical|high|medium|low|info|none (default high).
  • Exit code 0: passed. 1: at least one finding at or above --fail-on. 2: usage or config error, or a target could not be checked.
  • --list-rules prints every rule with its default severity.

GitHub Action

permissions:
  contents: read
  security-events: write   # only for the SARIF upload
steps:
  - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
    with: { persist-credentials: false }
  - uses: MrLouisWright/binary-sentinel@v1
    with:
      targets: 'dist/'
      fail-on: high
      sarif: binary-sentinel.sarif
  - uses: github/codeql-action/upload-sarif@v3
    if: always()
    with: { sarif_file: binary-sentinel.sarif }

Inputs: targets, fail-on, config, sarif, json, job-summary (Markdown report in the job summary, default true), args (extra CLI flags), profile. Outputs: markdown-file, exit-code.

Requirements

Node.js 18 or newer. No runtime dependencies.

Support

If this project is useful to you, you can support its development with a donation: Buy me a coffee. It helps keep these tools maintained, documented and free for everyone.

Credit (optional)

Free to use under MIT, no attribution required. If binary-sentinel helps you, a link back is appreciated:

<a href="https://louiswright.co.uk">Built with binary-sentinel by Louis Wright</a>
[![Built with binary-sentinel by Louis Wright](https://img.shields.io/badge/built%20with-binary--sentinel-blue)](https://louiswright.co.uk)

License

MIT © Louis Wright (Louis Wright)