Skip to content

zn-gate 1.9.1

Choose a tag to compare

@github-actions github-actions released this 16 Oct 14:18
· 54 commits to main since this release

zn-gate 1.9.1 finds more kinds of secrets with zn-gate scan and says what to do about each one, gives repairs that work in zn-gate check and zn-gate init (also after a Node.js version is removed), and closes ways an AI agent could start the guided zn-gate init. It also stops clearly on Node.js older than 18. Update with npm install -g zn-gate@1.9.1 and pip install -U zn-gate.

If a CI job runs zn-gate scan: the Node.js scan now reports more secret types, so a job that fails on findings can start failing on files that passed before. If you use the agent hooks: a prompt that holds an opaque Authorization: Bearer token is now blocked, and one in a tool's output is replaced.

Added

  • zn-gate scan finds more secrets, in Node.js and Python alike: values of --api-key=, --password=, --token=, --secret= and similar flags on a command line; quoted values assigned to a name that ends in password, secret, token or api key with =, :, := or => (also $password = "..."), when the value looks machine-generated; an opaque Authorization: Bearer token; and the password in https://user:password@host and ssh://user:password@host URLs, such as git remotes. A flag without a value, a reference ($TOKEN, ${API_KEY}), a placeholder (<token>, changeme) and a URL without a password are not reported. The Node.js scan now also reports the provider token formats the Python scan already reported (Slack, Stripe, Google, Hugging Face and the others the scrubber knows), with the same rule names.
  • zn-gate scan reads UTF-16 files that start with a byte order mark, and the private key files id_xmss and identity.
  • The scrubber also replaces an opaque Authorization: Bearer token (new type BEARER_TOKEN), as the Python package already did; zn's own __ZN_<NAME>__ markers are left alone. GitHub's fixed x-oauth-basic password (https://<token>:x-oauth-basic@host) is no longer a URL password in either package; the token in the user part is still found by its own pattern. A password that is only a reference (%NAME%, $NAME, ${NAME}, <name>, {{name}}) is not one either, while a literal password is redacted whatever the user part says. RULES_VERSION is now 2026-10-16.4 and SCRUB_RULES_VERSION 2026-10-16.3.

Changed

  • With Node.js older than 18, the zn-gate and zn commands you run stop with a short message that names the version and how to install Node.js 18 or later (exit code 1). Hooks, MCP servers and the zn run commands that zn's hooks write keep running and print a warning, so a check that works today is not turned off. Node.js 16 and 17 were never supported; some commands happened to run on them.
  • The Python zn-gate says that commands such as hooks, init, check and unlock are in the npm package and gives npx -y zn-gate init, instead of argparse's "invalid choice" error.
  • zn-gate check: when a hook cannot start because its Node.js or its zn-gate files are gone (for example after nvm uninstall), the fix it gives is a fresh npm install -g zn-gate and then zn hooks install <agent>, since the old Node.js took its zn with it. Claude Code set up with zn hooks install is told to run that again rather than to install the plugin. The zn-gate plugin together with the hooks of zn hooks install claude-code is reported as not protected, because both run and a broken one can block every prompt; the fix is zn hooks uninstall claude-code. A zn-gate plugin that is turned off is fixed with claude plugin enable zn-gate@usezn; next to zn's own hooks, which then are the ones that protect Claude Code, it is only noted. zn-gate init follows the same routes. A Claude Code prompt hook without onFailure: "block" gets a note.
  • The Python source distribution is now reproducible: two builds of the same commit with the same build tools give the same file, byte for byte, as the wheel and the npm tarball already did. CI and the release workflow build it twice and fail if the two differ.
  • zn-gate scan says "Secret found" for a secret, instead of calling it a threat, and adds one next step in plain words: run npx -y zn-gate env shadow <file> to move the values of a .env file into the local vault (the file name is shown only when it is made of plain characters and does not start with -, otherwise the command says <file>), run npx -y zn-gate secret set NAME to store any other value, move a private key out of the file, and rotate anything that was ever committed or shared. The value is never printed. In --format github, a secret's annotation is titled Secret found (<rule>) and its message is the next step; the summary line reads Found N secrets and M security threats. In --format json, each secret has a new next_step field and the report has a new total_secrets count; total_threats still counts every finding and the other fields are unchanged. Injection findings keep their wording.
  • The Node.js scan reports more secret types than before (the provider formats, Bearer tokens, URL passwords, command-line flags and assignments above), so a CI job that fails on findings (fail-on-threat, or the exit code of zn-gate scan) can start failing on files that passed before.
  • Agent hooks (Node.js): a prompt that holds an opaque Authorization: Bearer token is now blocked, and one in the output of a tool or MCP call is replaced, as for the other secret formats the scrubber knows. Use zn secret set NAME and the __ZN_NAME__ marker in its place.
  • Docs: the Python install steps say that Debian and Ubuntu need the python3-venv package for python3 -m venv.
  • Docs: what to do when your agent blocks every prompt because zn's hook cannot run (usually after Node.js is upgraded or moved): zn-gate check, reinstall, or turn zn off for that agent until it is fixed (docs/compat.md).
  • Docs: the README, docs/secrets.md and docs/check.md describe the 1.9.1 behaviour: "Secret found" and its next step in zn-gate scan, the secret types it finds (and that a CI job can start failing on files that passed before), the Node.js 18 message, the repair steps of zn-gate check, the guided zn-gate init without arguments, and zn hooks uninstall claude-code keeping other secrets MCP servers.

Fixed

  • zn hooks uninstall claude-code removed any user MCP server called secrets from Claude Code, also one that was not zn's. It now removes only zn's own server, recognised by its exact command (zn-gate's secrets-mcp), and says so when it leaves another one in place. zn hooks install no longer overwrites another secrets server that only mentions secrets-mcp.
  • An AI agent could start the guided zn-gate init despite the rule that keeps agents from running it: with a backslash or other characters the shell joins into one word, an option in capital letters, or npm exec, which keeps the options after the package for itself. These are refused now, and the guided zn-gate init stops with an error when it gets any argument. An agent variable such as CLAUDECODE that is set but empty now also counts as an agent. POLICY_RULES_VERSION is 2026-10-16.5.

How to verify these files: docs/verify-release.md