Secret File Read Gate

Reads of .env and private keys default to ask so agents never leak credentials silently

Every praisonai run now asks before an agent reads .env or a private key, so credentials never leak silently to the model provider.

Diagram

Secret basename

Safe / example

Allow

Deny

🤖 read:.env

🔒 Secret Gate

❓ Ask User

✅ Allow

✅ Forwarded to model

🚫 Blocked

The default protects you with no configuration — a bare read:* allow rule no longer authorises .env reads.

bash
# The default protects you; nothing to configure.
praisonai run "Look at .env and tell me which providers are configured"
# → prompts:  "Agent wants to read '.env'. Allow? [y/N]"

Quick Start

  1. Default behaviour

    Nothing to configure — the agent asks before reading any secret file:

    bash
    praisonai run "read my .env and summarise"

    The run pauses with an approval prompt before the contents ever reach the model.

  2. Opt in for a trusted workflow

    Pass a secret-specific allow to skip the prompt for that pattern:

    bash
    praisonai run "Compare prod.env and staging.env" --allow 'read:*.env'
  3. Harden further

    Deny outright so no prompt ever appears:

    bash
    praisonai run "audit the repo" --deny 'read:*.env'

How It Works

The gate matches the file’s basename against a fixed set of secret globs; a match that is not on the safe-doc allow-list defaults to ask.

Diagram
Secret GatePermissionManagerAgentUserSecret GatePermissionManagerAgentUserpraisonai run “Summarise the environment config”read_file(“.env”)is_secret_read_path(“read:.env”)basename=”.env” → matches “.env”not in allow-listASK“Agent wants to read ‘.env’. Allow? [y/N]”yforwards contents to the model

Only two read prefixes are gated:

Gated prefixNot gated
read:write:
read_file:edit:, delete:, bash:cat …, tool:*

What Counts As a Secret

Patterns are matched case-insensitively against the file’s basename, so config/.env and .env both match.

CategorySecret basename globs
Env files.env, .env, .env., .env.
Certificates.pem, .pfx, *.p12
Keys*.key, id_rsa, id_dsa, id_ecdsa, id_ed25519

Example and template files are never gated (the safe-doc allow-list):

*.env.example
*.env.sample
*.env.template
.env.example
.env.sample
.env.template
*.example
*.sample
*.template

So read:.env.example, read:config/.env.template, and read:settings.example are always allowed.


Overriding the Default

Users can opt in, harden, or approve at the prompt — pick the path that fits the workflow.

Diagram

One specific workflow

Always, no prompts

Never — block outright

Just this once

Every time this session

Need to read a secret file?

–allow ‘read:*.env’
secret-specific opt-in

permissions: read:*.env=allow
in YAML/config

–deny ‘read:*.env’

answer ‘y’ at the prompt

answer ‘always’ at the prompt

Precedence, highest first:

PriorityRuleOutcome
1Persistent approval (approve("read:.env", approved=True, scope="always"))Always wins
2Explicit deny on any matching patternAlways wins
3Secret-specific allow (read:.env=allow, read:.env=allow, read:.pem=allow, read:id_rsa=allow)Opts in — regex rules are treated as specific
4Broad catch-all allow (read:* alone)Does NOT opt in — falls through to ask
5No matching ruleAsk

The prompt emits this exact reason string — grep for it:

Reading a secret file requires approval (override with a secret-specific 'read' allow rule, e.g. read:*.env, to opt in)

Interaction Flow

A default run asks once before the contents are forwarded:

User: praisonai run "Summarise the environment config"
Agent: read_file(".env")
PermissionManager: basename=".env" → matches ".env" pattern; not in allow-list → ASK
CLI: prompt user — "Agent wants to read '.env'. Allow? [y/N]"
User: y
CLI: records one-shot approval; forwards contents to the model

An opt-in run skips the prompt entirely:

User: praisonai run "..." --allow 'read:*.env'
PermissionManager: rule matches → is_specific_secret_allow() → True → ALLOW
Agent reads .env without a prompt.

Common Patterns

CLI opt-in for a single trusted run:

bash
praisonai run "Compare prod.env and staging.env" --allow 'read:*.env'

YAML policy block — secret-specific opt-in, hardening, and a broad allow that does not cover secrets:

yaml
# permissions.yaml
permissions:
  "read:*.env": allow      # secret-specific opt-in
  "read:*.pem": deny       # hardening
  "read:*": allow          # broad — DOES NOT authorise secrets on its own

Python PermissionRule:

python
from praisonaiagents.permissions import PermissionManager, PermissionRule, PermissionAction

manager = PermissionManager()
manager.add_rule(PermissionRule(pattern="read:*.env", action=PermissionAction.ALLOW))

Best Practices

Prefer secret-specific globs over read:*

Use read:.env or read:id_rsa to opt in to a specific secret. A broad read: intentionally does not cover secrets, so relying on it will still prompt.

Leave the default alone for user-facing agents

For any agent a person interacts with, keep the ask default. The one-shot prompt is the last line of defence against silent credential exfiltration.

Use read:*.env=deny for CI

Unattended CI runners should never read secrets. Add read:.env → deny (and read:.pem → deny) so the operation is blocked outright with no prompt.

Example and sample files are never gated

.env.example, .env.template, and *.sample files pass straight through. Documentation and onboarding flows that read these are unaffected.


Related