Skip to content

Permission rules: an unreadable or unparseable settings.json drops its deny rules instead of failing closed #4282

Open

Description

@KuSh

RTK loads permissions from the Claude Code settings files. When one of those files exists but cannot be read or parsed, its rules are skipped and matching carries on as if they were not there. A command that file denies then gets the Default verdict (exit 3) instead of Deny (exit 2).

Measured

rtk rewrite "git push origin main" on develop (c75f1590), with CLAUDE_CONFIG_DIR pointing at a directory whose settings.json holds {"permissions":{"deny":["Bash(git push *)"]}}:

settings.json exit stderr
valid 2 (denied) —
unparseable (a trailing comma after the array) 3 [rtk] warning: failed to parse permissions from <path>
unreadable (chmod 000) 3 (nothing)

Two different gaps:

  • An unreadable file is dropped with no warning at all. The read-failure branch in src/hooks/permissions.rs moves on to the next file without saying anything.
  • An unparseable file warns, but nobody sees it. The shell hooks call rtk rewrite "$CMD" 2>/dev/null (hooks/claude/rtk-rewrite.sh, hooks/cursor/rtk-rewrite.sh), so the warning is discarded before it reaches the user.

In both cases the deny list the user wrote stops applying, and the verdict degrades rather than failing closed.

Who this reaches

Claude Code applies its own copy of these rules, so it does not depend on RTK alone. For the delegates where RTK is the only thing reading ~/.claude/settings.json — the ones that shell out to rtk rewrite and do not distinguish exit 0 from 3 (hooks/pi/rtk.ts, also used by omp; hooks/hermes/rtk-rewrite/__init__.py; hooks/opencode/rtk.ts) — a broken file means the whole deny list is void. A change that relaxes Default for a host, such as #3909 for OpenClaw, would turn these commands from a prompt into an allowed rewrite.

Shape of a fix

A settings file that exists but cannot be read or parsed should not be indistinguishable from "no rules". Failing closed would mean treating that load failure as Ask — a verdict nothing relaxes — rather than letting every command fall to Default. The unreadable branch also needs the same warning the parse branch already gives, and a warning that only reaches /dev/null in the common path may be worth surfacing some other way.

Related: #1482 (the same silent fallback for rtk's own config.toml), #4281 (deny rules missing wrapped or env-prefixed commands).

Activity

  1. rtk-wshm-sync-bot commented on Sep 26, 2026

    @rtk-wshm-sync-bot

    wshm · Automated triage by AI

    🔍 Automated Triage

    🐛 Category bug
    🟠 Priority high
    🎯 Confidence 90%

    Summary

    An unreadable or unparseable permissions settings.json silently drops deny rules and falls back to Default instead of failing closed to Ask.

    📁 Relevant files
    • src/hooks/permissions.rs
    • hooks/claude/rtk-rewrite.sh
    • hooks/cursor/rtk-rewrite.sh
    • hooks/pi/rtk.ts
    • hooks/hermes/rtk-rewrite/__init__.py
    • hooks/opencode/rtk.ts

    Suggested Actions

    1. Make unreadable/unparseable settings.json load failures resolve to Ask, not Default, in src/hooks/permissions.rs
    2. Add the same warning to the unreadable-file branch that the parse-failure branch already emits
    3. Stop discarding the warning: hooks/claude/rtk-rewrite.sh and hooks/cursor/rtk-rewrite.sh pipe rtk rewrite stderr to /de…
    4. Cross-check with Partial TOML Sub-Config Sections Silently Fall Back to Full Defaults #1482 (same fallback pattern for config.toml) and Permission rules: deny and ask miss commands behind an env assignment or a process wrapper that Claude Code strips #4281 (related deny-rule gaps)

    Triaged automatically by wshm · This is an automated analysis, not a human review.

  2. TechWizard9999 commented on Sep 27, 2026

    @TechWizard9999
    Contributor

    Hi @KuSh , Can I work on this issue
    Could you please assing me this

  3. KuSh commented on Sep 27, 2026

    @KuSh
    CollaboratorAuthor

    Hi @KuSh , Can I work on this issue Could you please assing me this

    Check #4287, it seems @mrhard9090 already pushed something

  4. KuSh commented on Oct 18, 2026

    @KuSh
    CollaboratorAuthor

    #4287 covers the read and parse failures. One case outside its hunks still drops rules with no warning: a settings file that is valid JSON but has the wrong shape. json.get("permissions") and append_bash_rules skip anything that is not an object or an array of strings.

    On develop e542dca0b and on #4287 merged, rtk rewrite "git push origin main" with CLAUDE_CONFIG_DIR/settings.json set to:

    • null → exit 3 with no warning; exit 0 (rewrite allowed) under RTK_REWRITE_HOST=openclaw
    • {"permissions":{"deny":"Bash(git push *)"}} (a string, not an array) → the same: exit 3 with no warning, exit 0 under RTK_REWRITE_HOST=openclaw

    The same fail-closed Ask as an unparseable file would cover it.

  5. KuSh commented on Oct 23, 2026

    @KuSh
    CollaboratorAuthor

    #4287 is now merged on develop, not in a release yet. An unreadable or unparseable settings file now prints a warning and the command is left to ask, also under RTK_REWRITE_HOST=openclaw.

    The wrong-shape case from my previous comment is unchanged on develop 2dabd83: {"permissions":null}, or a deny written as a string instead of an array, still drops the rules with no warning and exits 0 under RTK_REWRITE_HOST=openclaw. Separately, the legacy rtk-rewrite.sh hook sends rtk rewrite's stderr to /dev/null (line 59), so anyone still on that hook never sees the new warning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions