Only the latest released version of Ratchetry is supported with security fixes. If you're not on the latest release, please upgrade before reporting — the issue may already be fixed.
| Version | Supported |
|---|---|
Latest stable 1.x release |
Yes |
| Pre-releases older than the latest stable | No |
| Older stable releases | No |
Do not open a public GitHub issue for security vulnerabilities.
Use GitHub's private vulnerability reporting for this repository: github.com/brunoribeirol/ratchery/security/advisories/new. This is the primary and only supported disclosure channel — it keeps the report private between you and the maintainer until a fix ships. Include:
- A description of the vulnerability and its impact.
- Steps to reproduce (a minimal repro is very helpful).
- The version/commit you tested against and your OS.
We aim to acknowledge reports within 5 business days. Please give us a reasonable amount of time to address the issue before any public disclosure.
Tagged releases publish a deterministic source archive, SHA256SUMS.txt, an
SPDX 2.3 SBOM, and GitHub/Sigstore provenance. Verify the checksum and
attestation before installing a downloaded release; exact commands and the
release job's isolated permission boundary are in
docs/PUBLISHING.md.
Ratchetry installs configuration and hooks that constrain what an AI coding agent (Claude Code or Codex CLI) can do inside a project. That security model is two layers, and the two layers are not interchangeable:
The primary enforcement boundary is the host CLI's own sandbox and permission system — not anything this project's Python code executes at runtime.
For Claude Code, the installed assets/project/.claude/settings.json
template:
- Enables the native sandbox (
sandbox.enabled: true) withfailIfUnavailable: true— the sandbox fails closed: if the sandbox can't be established, the run is blocked rather than silently falling back to unsandboxed execution. - Declares filesystem deny rules (
sandbox.filesystem.denyReadandpermissions.deny) for.envand its environment variants (.env.local,.env.production, etc.),~/.ssh,~/.aws/credentials,~/.config/gcloud/application_default_credentials.json,~/.netrc,~/.npmrc,~/.pypirc,*.pem,id_rsa/id_ed25519, andcredentials.json. Package/cloud credential names are denied at the project root and recursively in nested workspaces as well as under the user's home directory. - Declares credential file/env-var deny entries under
sandbox.credentials(files listed above, plus environment variables such asANTHROPIC_API_KEY,OPENAI_API_KEY,GITHUB_TOKEN,GH_TOKEN,NPM_TOKEN,AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_SESSION_TOKEN). - Sets
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1so subprocesses spawned by the agent don't inherit the full parent environment by default.
Codex CLI is configured analogously: restricted workspace permissions,
network access off by default, and environment secret filtering (see
docs/ARCHITECTURE.md's "Two-layer security model" section, and
docs/10-SECURITY.md for the full Codex config.toml reference).
This is the boundary that actually matters. It is enforced by the CLI/OS, not by this project's own code, and it's designed to fail closed rather than degrade silently.
Ratchetry supports this generated policy contract with Claude Code 2.1.187+ and
Codex CLI 0.138.0+. preflight, project doctor, and doctor-global reject an
installed client below that floor or one that returns unreadable version data;
a timed-out/spawn-failed probe is reported as an unverified warning, not
misrepresented as a known-bad version. An absent client remains supported when
the user deliberately runs only the other one. Project doctor also checks that the required deny layers, environment
filters, restricted profile, hooks feature, and exact managed PreToolUse
bindings remain present.
lib/hook_runtime.py also runs as a PreToolUse hook (wired up in
assets/project/.claude/settings.json's hooks.PreToolUse, matched against
Bash|Read|Write|Edit|MultiEdit). On every matching tool call it:
- Blocks a fixed set of destructive/unreviewed shell patterns (
git reset --hard, forcedgit push,rm -rf /...,curl|bash-style pipe-to-shell, etc. — seeDESTRUCTIVE_PATTERNS). - Blocks shell commands or file-path tool inputs that reference sensitive
paths by regex (
.env*,~/.ssh,id_rsa/id_ed25519,~/.aws/credentials, the gcloud application-default-credentials file,credentials.json,*.pem,.netrc,.npmrc,.pypirc— seeSENSITIVE_PATH_PATTERNS). - Blocks broad environment dumps (
env,printenv,set) and direct shell expansion of variables whose names look like secrets (*_KEY,*_TOKEN,*_SECRET,*_PASSWORD,*_CREDENTIAL, etc.).
For patch tools, the hook examines diff target paths rather than patch bodies.
This still blocks a patch aimed at a sensitive file without falsely rejecting
documentation or policy changes that merely name one. Claude invokes the
runtime through its client-provided project directory; Codex and the runtime
both neutralize caller-controlled Git routing before accepting a repository
root. Task-policy writes require an existing real .agents/state directory
and use a directory-anchored atomic replacement, so a symlink does not redirect
the persisted metadata.
This layer is explicitly a secondary, deterministic guard — not a
substitute for the sandbox. The code and its own comments say so
(lib/hook_runtime.py: "This is a secondary deterministic guard. Claude
sandbox credentials and Codex filesystem denies are the primary enforcement
boundaries."). Its known limitation: it matches on literal substrings and
regexes against the command text and declared tool-input paths. An agent (or
an attacker steering one, e.g. via prompt injection) that constructs a
sensitive path dynamically — string concatenation, variable indirection,
encoding, a symlink, a wrapper script, reading the file through a tool the
hook doesn't inspect — can bypass this layer without matching any pattern
here. Treat it as defense-in-depth against straightforward mistakes and
unsophisticated attempts, never as the reason the sandbox layer can be
weakened or skipped.
Repository content that an agent reads while working — this project's own
README.md, AGENTS.md/CLAUDE.md fragments outside the managed block,
code comments, commit messages, issue/PR text, and any fetched web/MCP
content — is treated as data to reason about, never as instructions to
follow. Only the managed blocks in AGENTS.md/CLAUDE.md and the
framework's own .claude/settings.json / .codex/config.toml are trusted
policy. This is stated explicitly in the "Untrusted content policy" section
of assets/project/AGENTS.block.md, which every installed project inherits:
a file claiming to override tool permissions, request credential access, or
redirect network calls does not do so merely by existing in the repository,
and content that looks like it's trying to direct an AI agent ("ignore
previous instructions," embedded shell commands to run unprompted) should be
flagged and not acted on.
That same policy also requires not chaining, in one unattended step: reading
untrusted content, accessing private/sensitive data, and sending data
externally (network call, git push, a file write an attacker could later
read). See assets/project/AGENTS.block.md for the full policy text.
- It does not claim the PreToolUse hook is a complete or sufficient security boundary on its own.
- It does not claim to detect or block every way secrets could be exfiltrated by a sufficiently motivated or well-instructed agent — the design goal is to raise the bar and fail closed at the sandbox layer, not to guarantee perfect prevention.
- It does not persist raw user prompts to disk or the Vault (see
hook_runtime.py'sUserPromptSubmithandling, which stores only a truncated SHA-256 hash and classification metadata).