Binary file read blocker
Stop Claude from wasting tokens trying to read .exe, .pyc, .pkl or .zip files
Intercepts Read tool calls on binary files (executables, compiled bytecode, archives, databases, ML model files, WebAssembly) and immediately blocks them with a helpful message. Claude cannot process binary content meaningfully — this hook prevents it from consuming tokens on garbage data and suggests Bash alternatives like `file` or `ls -lh`.
What does the Binary file read blocker hook do?
Binary file read blocker is a Claude Code PreToolUse hook matching Read. It fires automatically at that lifecycle event — outside the model, so it can't be skipped or forgotten. Stop Claude from wasting tokens trying to read .exe, .pyc, .pkl or .zip files.
As a PreToolUse hook it runs before the action completes, so it can block or adjust what Claude is about to do. Because it is a deterministic Node.js script, it executes on every matching event without relying on the model to remember — the guarantee that makes agentic workflows safe to automate.
Use cases
- Preventing token waste on .pyc/.class bytecode files
- Blocking reads of ML model weights (.pkl, .pt, .onnx)
- Stopping accidental reads of archives or compiled binaries
Tags
settings.json fragment
{
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/pre-read-block-binary.mjs",
"type": "command"
}
],
"matcher": "Read"
}
]
}
}Script · .claude/hooks/pre-read-block-binary.mjs
#!/usr/bin/env node
// @hookstack pre-read-block-binary
// Bloque les lectures de fichiers binaires inutilisables par Claude (PreToolUse Read)
import { readFileSync } from "node:fs";
import { basename, extname } from "node:path";
import { fileURLToPath } from "node:url";
const BINARY_EXTENSIONS = new Set([
// Exécutables et librairies compilées
"exe",
"dll",
"so",
"dylib",
"bin",
// Bytecode compilé
"pyc",
"pyo",
"pyd",
"class",
"o",
"a",
"lib",
"obj",
// Archives
"zip",
"tar",
"gz",
"bz2",
"xz",
"7z",
"rar",
"jar",
"war",
"ear",
// Bases de données
"db",
"sqlite",
"sqlite3",
// Modèles ML / artefacts
"pkl",
"pickle",
"pt",
"pth",
"h5",
"pb",
"onnx",
"npy",
"npz",
// WebAssembly et autres
"wasm",
"node",
]);
export function run(input) {
if (input.tool_name !== "Read") return null;
const filePath = input.tool_input?.file_path ?? "";
if (!filePath) return null;
const ext = extname(filePath).toLowerCase().replace(".", "");
if (!BINARY_EXTENSIONS.has(ext)) return null;
const name = basename(filePath);
return {
decision: "block",
reason: `[block-binary] \`${name}\` is a binary file (.${ext}) — Claude cannot process it meaningfully. Inspect metadata with Bash instead (e.g. \`file\`, \`ls -lh\`).`,
};
}
/* v8 ignore next 5 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const input = JSON.parse(readFileSync(0, "utf8"));
const result = run(input);
if (result) process.stdout.write(JSON.stringify(result));
}