glimfly
security updated

What is the principle of least privilege? (why your agent keeps asking permission)

In one sentence:The principle of least privilege means every key and account gets the minimum access it needs to do its job, so one leak or one bad command can't take everything down.

What it actually is

The principle of least privilege says every key and account should get the minimum access it needs to do its job, and nothing extra “just in case.” A key that only needs to read data gets read access. A tool that only touches one folder gets that folder. When something goes wrong later (a leak, a bug, an agent misfire), the damage stops at the edge of what that one credential was allowed to do.

Think of a valet key. You hand your car to a valet with the key that starts the engine but won’t open the trunk or the glove box. Nothing against the valet; parking a car doesn’t require access to everything in it. Least privilege is that same decision applied in advance to every credential in your project, from API keys and tokens to database roles.

The opposite habit is handing out master keys because they always work. A master key does make permission errors disappear while you build. It also means that when it leaks (and keys leak constantly, see exposed API keys), whoever finds it gets everything at once.

Why your AI just did this

If you use Claude Code, you live inside least privilege every session. That’s what the permission prompts are. The tool runs a tiered system: reading files in your project requires no approval, while file edits and shell commands beyond a built-in read-only list prompt you before they run. The agent starts with minimal power, and you grant more one action at a time. A bypassPermissions mode exists to skip the prompts, and Anthropic’s own docs say to use it only in isolated environments like containers or VMs, where a bad command can’t reach anything that matters. That’s the same idea as sandboxing: assume mistakes will happen, and shrink what they can touch.

Agents also push against least privilege, which is when you need the term most. A classic case: your Supabase query fails because Row Level Security blocks it, and your agent suggests switching to the service role key because that will make the error go away. It will, the way a master key opens a locked door. The service role key bypasses RLS entirely, so the app now trusts every request. The better fix is a policy that lets signed-in users read their own rows, with the big key staying on the server.

When you’ll run into it

The most familiar sighting is Claude Code’s prompt before a command: the panel asking you to approve the action once, approve it permanently (“Yes, don’t ask again”), or reject it. Choosing “don’t ask again” for a Bash command saves a rule for that command in .claude/settings.local.json, scoped to that repository.

You’ll also meet it in the Supabase dashboard, which offers two kinds of keys. Publishable keys (sb_publishable_..., or the legacy anon key) are built for browsers and safe to expose. Secret keys (sb_secret_..., or the legacy service_role key) grant full access to your data, bypass Row Level Security, and must stay server-side. Supabase enforces this one mechanically: a secret key called from a browser gets an HTTP 401 no matter what.

GitHub’s token screen is another one. Fine-grained personal access tokens let you pick specific repositories and specific permissions (contents read-only, for example), and GitHub recommends them over classic tokens, which grant broad scopes across your account. And the last place you meet least privilege is the day a key leaks, when scope decides whether the story is “someone read a config file” or “someone downloaded the whole database.”

What to check

  • Ask what a key can do before you paste it anywhere; names like anon, secret, and service_role are the first hint
  • Keep the Supabase secret or service_role key in server code only, loaded from an environment variable, never in anything the browser downloads
  • Scope new tokens at creation: one repository, the narrowest permissions, an expiry date
  • Push back when your agent wants broader access to silence an error; ask it what minimum permission the task needs
  • Save “don’t ask again” approvals for narrow commands like npm test, and keep prompts on for anything that can delete or deploy
  • Rotate any leaked key immediately, then check what it was scoped to reach

Say it like a dev

Instead of: “just give it full access so it stops erroring” Say: “Scope this key to read-only on the one resource we need. If something still fails, tell me which specific permission is missing.”

Instead of: “the database keeps blocking my query, use the admin key” Say: “RLS is blocking this query. Write a policy that lets authenticated users read their own rows, and keep the service role key server-side.”

Instead of: “make Claude stop asking me for permission every time” Say: “Add an allow rule for npm test so that one command runs without a prompt, and leave approval on for everything else.”

People actually ask

“Why does Claude Code ask for permission before every command?”

Claude Code applies least privilege to itself. Reading files in your project needs no approval, but editing a file or running a shell command (beyond a built-in list of read-only ones) prompts you first, so the agent only ever holds the power you granted for that specific action. You can approve a specific command permanently (it saves a rule in .claude/settings.local.json), which is safer than switching to bypassPermissions mode, a setting the docs say to use only in isolated environments like containers or VMs.

“Is it safe to use my Supabase service role key in my app?”

No. The service role key (and the newer sb_secret_ keys) grants full access to your data and bypasses Row Level Security, so it belongs in server-side code only, loaded from an environment variable. Browser code should use the publishable key (sb_publishable_, or the legacy anon key), which is designed to be public. Supabase even rejects secret keys sent from a browser with a 401 error.

“What happens if an API key with too many permissions leaks?”

Whoever finds the key can do everything the key can do, and leaked keys get found fast by bots scanning public code. An over-scoped key turns a small mistake into full access: a leaked read-only key exposes some data, while a leaked admin key hands over your whole database. Least privilege limits that damage in advance, and rotation (revoking the key and issuing a new one) is the fix once a leak happens.

Related terms

Go deeper

Checked against

free tool · no signup

Just met this in a real session? Glim reads it in plain words.

Paste what your agent just did, a git diff, your terminal, or its summary, and Glim tells you what changed and what to check before you ship. Nothing stored.

Explain my session →