ES · Leer en español Explore for free

Template · Intermediate · 5 min

Claude Code settings.json checker: find permission risks

Paste your Claude Code settings.json and see every permission risk with its level, a plain explanation and the link to the official documentation.

Cover: Claude Code settings.json checker: find permission risks

Tested with Claude Code 2.1.316 · reviewed

See the files on GitHub Free · MIT license

Try it here

It runs in your browser: nothing is sent to any server.

    What's included

    The tool is above: you paste a .claude/settings.json, ~/.claude/settings.json or settings.local.json, choose which file it is and in a second you see every risk sorted by level (critical, high, medium, low, info), with its explanation and the link to the official page that backs it. There are 21 rules, each based on a specific sentence from the Claude Code 2.1.316 pages on permissions, permission modes, sandbox and settings reference, and all of them have automated tests. It runs entirely in your browser: the text never leaves your machine. The findings are written in Spanish; the level names are crítico (critical), alto (high), medio (medium), bajo (low) and info. The English version in the repository's en/ folder shows them in English.

    The code (a single JavaScript file with no dependencies, an example index.html, its Node tests and the example files) is in the free repository ctrlia-comprobador-settings.

    Critical and high rules

    IDLevelWhat it detects
    R01critical (user) · info (project/local)defaultMode: "bypassPermissions": in the user file, every session with no checks (the docs limit it to isolated containers or VMs); in project or local it only reports that it is ignored
    R03highskipDangerousModePermissionPrompt: true: removes the bypass confirmation
    R05criticalBash or Bash(*) in allow: the docs say it equals every command
    R06highWildcards that amount to running code: interpreters and launchers (python3, node, bash -c, npx, uvx, uv run, docker exec, make, sudo, ssh, git…) followed only by * or by one option and *
    R09highNo Read deny for .env
    R13highenableAllProjectMcpServers: true
    R14highmcp__* in allow
    R16highadditionalDirectories with / or the home folder
    R17critical (project) · highKeys in the env block; critical if the file is a project file, because it is committed to git

    On R06, the docs explain that wrappers such as devbox run or docker exec are not stripped from the command and that Bash(git * main) includes git -c, which runs a program.

    Medium, low and informational rules

    IDLevelWhat it detects
    R07medium* before the subcommand (Bash(git * main), Bash(* --version)): Claude Code already warns at startup since 2.1.246 because it approves inserted options
    R08lowNo space before the *: Bash(ls*) approves lsof
    R10lowA .env deny without .env.* (leaving .env.local, .env.production)
    R11mediumA curl/wget deny or ask used as a network block: the docs show it does not stop /usr/bin/curl or sh -c; the real block is the sandbox
    R12mediumWrite(path), Glob(path), NotebookEdit(path) or MultiEdit(path) rules: accepted but they never match; use Edit(path) and Read(path)
    R15mediumWebFetch without a domain in allow
    R02infodefaultMode: "auto" in project or local (ignored)
    R04infoSuggestion of disableBypassPermissionsMode: "disable" in the user file
    R18infohooks, apiKeyHelper or statusLine in a project file: they run even with claude -p in an untrusted folder
    R19infoSandbox turned off
    R20lowSandbox on but allowUnsandboxedCommands not set to false
    R21infoReminder: allow rules in a project file only apply once you accept to trust the folder

    Honest limits

    It reviews the text of the rules; it does not analyze your system:

    1. It does not read your hooks or scripts, it only warns that they exist.
    2. The list of wrappers is fixed and may miss some (for example your own script that accepts commands).
    3. It does not merge the four scopes the way Claude Code does; that is why you should also check /permissions.
    4. Read deny rules only protect against Claude's tools and the file commands Claude Code recognizes (cat, head, sed…), not against a Python or Node program that opens the file on its own, as the docs say; that is what the sandbox is for.
    5. "No findings" does not mean safe.

    Each finding links to the official page so you do not have to take our word for it. The rules are reviewed every 30 days against the CHANGELOG, because the permission system changes in almost every version.

    Privacy and technical design

    A single script served from ctrlia.dev, loaded with defer, with no inline code, no fetch, no storage and no dependencies. The JSON is parsed with JSON.parse (never eval) and the results are rendered with textContent, so a file with HTML or scripts inside cannot run. The analyze(text, scope) function in the repository's en/checker.js is pure and returns {error} or {findings: [{id, level, text, doc}]}, which makes it testable with Node and reusable, for example in a hook. Accessibility: a label on the selector and on the text area, a real button, results in a list with aria-live="polite" and levels shown as text, not only as color. Even though nothing is sent, remove keys before pasting.

    How to use it

    1. Choose which file it is

    It matters, because Claude Code treats each scope differently. bypassPermissions or auto in .claude/settings.json or settings.local.json has no effect (the session starts in Manual), but in ~/.claude/settings.json it does; and allow rules in a project file only apply once you accept to trust the folder, while deny and ask always apply.

    2. Paste the content and press "Comprobar" (Check)

    If it is not valid JSON it tells you where the error is: the file does not allow comments or trailing commas.

    3. Read the findings from critical to info

    Open the link on each one: it is the official page that explains it.

    4. Fix and check again

    Fix things with the Claude Code permissions recipe and paste the file again. To see what is really loaded (adding up every scope), run this inside Claude Code:

    /permissions

    It lists every rule and the file it comes from. The tool looks at one file at a time; Claude Code merges the user, project, local and managed ones.

    The files

    A project .claude/settings.json with typical mistakes (en/example.json in the repository):

    {
      "permissions": {
        "allow": ["Bash(npm run *)", "Bash(python3 *)", "Bash(git * main)", "WebFetch"],
        "deny": ["Bash(curl *)", "Write(./secrets/**)"]
      },
      "enableAllProjectMcpServers": true,
      "env": { "STRIPE_SECRET_KEY": "sk_test_1234567890" }
    }

    Real output from the repository's en/checker.js with that example, project scope (the tool on this page still shows the findings in Spanish):

    R06 · high: "Bash(python3 *)" amounts to running arbitrary code: python3 runs whatever comes after it. Write the exact command (e.g. Bash(python3 -m pytest *)).
    R07 · medium: "Bash(git * main)" has a * before the subcommand: it also approves options like git -c, which run programs. Put the * at the end.
    R09 · high: No deny for .env: add "Read(.env)" and "Read(.env.*)" (a bare name covers any depth). It blocks Claude's tools and cat/head/sed, not a script that opens the file: for that, use the sandbox.
    R11 · medium: "Bash(curl *)" is not a network block: it does not stop /usr/bin/curl, sh -c "curl …" or other programs. To really block the network, turn on the sandbox with its domain list.
    R12 · medium: "Write(./secrets/**)" never matches: paths are only checked with Edit(...) and Read(...). If it was a deny, it does not protect you.
    R13 · high: enableAllProjectMcpServers: true approves without asking every server in .mcp.json (in the project file, once you accept to trust the folder).
    R15 · medium: "WebFetch" lets it download any URL without asking: a door for injected instructions. Limit it to specific domains.
    R17 · critical: env.STRIPE_SECRET_KEY has a value that looks like a secret in a file that is committed to git. Use system environment variables or apiKeyHelper.
    R19 · info: Sandbox turned off. It is the only thing that blocks file reads and network for every process, not just for Claude's tools (/sandbox).
    R21 · info: The allow rules in this file only apply once you accept to trust the folder; deny and ask always apply.

    In short: Bash(python3 *) runs arbitrary code (R06); the * before the subcommand also approves git -c (R07); there is no .env deny (R09); a curl deny is not a network block (R11); Write(...) never matches (R12); every .mcp.json server is approved (R13); WebFetch without a domain (R15); a secret in a file committed to git (R17); sandbox off (R19); and the folder-trust reminder (R21). On the page the findings are sorted from critical to info, each with its link.

    A starting point that passes the checker with no high or critical findings (en/starting-point.json, for .claude/settings.json): allow with exact commands, ask for git push and git commit, deny for .env, .env.*, secrets/** and keys, and the sandbox on in strict mode.

    {
      "$schema": "https://json.schemastore.org/claude-code-settings.json",
      "permissions": {
        "allow": [
          "Bash(npm run test)",
          "Bash(npm run lint)",
          "Bash(python3 -m pytest *)",
          "Bash(git status *)",
          "Bash(git diff *)",
          "Bash(git log *)"
        ],
        "ask": ["Bash(git push *)", "Bash(git commit *)"],
        "deny": [
          "Read(.env)",
          "Read(.env.*)",
          "Read(./secrets/**)",
          "Read(**/*.pem)",
          "Read(**/*.key)"
        ]
      },
      "sandbox": {
        "enabled": true,
        "allowUnsandboxedCommands": false
      }
    }

    Before copying it, adapt the commands to your project: a rule that does not match neither protects you nor saves you prompts. With the sandbox on and autoAllowBashIfSandboxed at its default, the docs say commands inside the sandbox run without asking: the boundary becomes the sandbox, not the allow list. In your user file (~/.claude/settings.json) also add:

    {
      "permissions": { "disableBypassPermissionsMode": "disable" }
    }

    The repository has all the tool's files:

    FileWhat it is
    en/checker.jsThe analyze function (21 rules) and the interface, no dependencies and no inline code
    en/index.htmlExample page with the form, loading checker.js with <script src>
    en/tests.jsNode checks
    en/example.jsonThe file with typical mistakes shown above
    en/starting-point.jsonThe starting configuration shown above

    The Spanish originals (comprobador.js, pruebas.js, ejemplo.json…) are at the repository root.

    To try it on your machine:

    git clone https://github.com/carlosp5751258-lgtm/ctrlia-comprobador-settings
    cd ctrlia-comprobador-settings/en
    node tests.js          # → ok: checker

    Then open en/index.html in your browser. To understand each rule in depth, see the security hooks and MCP for developers recipes. If you also want a CLAUDE.md, use the CLAUDE.md generator. Sources: permissions, permission modes, settings, settings reference, sandboxing, headless mode, security and the CHANGELOG.

    FAQ

    Why is Bash(python3 *) dangerous if I only want to run my scripts?

    Because it also approves python3 -c "…" with any code. Write the rule with a fixed argument: Bash(python3 -m pytest *) or Bash(python3 scripts/build.py).

    I put bypassPermissions in .claude/settings.json and it does nothing. Why?

    That is the documented behavior: from that file and from settings.local.json it has no effect and the session starts in Manual. It only works from ~/.claude/settings.json or the command line, and the docs limit it to isolated environments.

    Does a Bash(curl *) deny block the internet?

    No. The docs show it does not stop /usr/bin/curl or sh -c 'curl …'. To really block the network, use the sandbox with its domain list.

    Does Read(.env) protect my .env from everything?

    From Claude's tools and from commands like cat or sed, yes. From a script that opens the file on its own, no: that is what the sandbox is for.

    Is my file sent to any server?

    No. The analysis happens in your browser. Even so, delete keys before pasting: they should not be in settings.json.

    I get no warnings. Am I safe?

    Not necessarily: the tool reviews the text of the rules, not your hooks or scripts, and it looks at one file at a time. Also check /permissions inside Claude Code.

    The whole library