Skip to content

runtime protection treats protectedPaths as a file allowlist #81

@MN755

Description

@MN755

Description

agentguard protect and OpenClaw runtime protection treat protectedPaths as the filesystem_allowlist for file operations.

That flips the meaning of the default policy in src/runtime/policy.ts: instead of only gating sensitive paths like .env and .ssh, ordinary workspace files are treated as disallowed because they are not in that list.

Steps to Reproduce

  1. Use the default local runtime policy from src/runtime/policy.ts.
  2. Run:
    printf '{"tool_name":"Read","tool_input":{"file_path":"/workspace/src/index.ts"}}' \
      | AGENTGUARD_AGENT_HOST=codex agentguard protect --json
  3. Or let registerOpenClawPlugin() handle a normal Read / write / scaffold event with runtimeProtection enabled.
  4. evaluateLocalAction() maps policy.protectedPaths into filesystem_allowlist, and ActionScanner.handleFileOperation() denies any path outside that allowlist with PATH_NOT_ALLOWED.

Expected Behavior

Sensitive paths like .env, .ssh, AWS credentials, etc. should require approval or be blocked.

Ordinary workspace files should not be denied just because they are not listed in protectedPaths.

Actual Behavior

Normal file reads and writes can surface as PATH_NOT_ALLOWED, which becomes require_approval in the local runtime path and then gets surfaced by the hook layer.

Environment

  • Node.js version: any supported version
  • OS: any
  • AgentGuard version: 1.1.10
  • Platform (Claude Code / Codex CLI / other): reproduced from the Codex/OpenClaw runtime path

Additional Context

The key path looks like this:

  • src/runtime/policy.ts defines protectedPaths as a sensitive-path list.
  • src/runtime/evaluator.ts passes that list into effective_capabilities.filesystem_allowlist.
  • src/action/index.ts, handleFileOperation(), interprets filesystem_allowlist as a real allowlist and denies everything else.

There is also a mismatch with registerOpenClawPlugin(): workspacePaths are only applied to the fallback defaultCapabilities, but the default runtime-protection path calls protectAction() directly, so it never sees that workspace allowlist.

I think the narrow fix is to keep protectedPaths as a deny/approval list and pass a separate workspace/file allowlist into runtime file-operation evaluation, or skip the PATH_NOT_ALLOWED branch for the default local runtime policy unless an explicit file allowlist was configured.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions