◉GEMINI LABJP
●3.8 FLASH — 3.7 Flash was deprecated on Oct 8. Requests to the old model are routed to 3.8 Flash automatically●NANO 2.1 — gemini-nano-banana-2.1 is GA. gemini-3.1-flash-image is deprecated with no shutdown date yet●DEADLINE — veo-3.1 previews and gemini-omni-flash-preview shut down Oct 22; the Deep Research agent follows Oct 23 (12-13 days left)●Q&A — Users report Gemini CLI marks a subagent run as a success even after it stops at MAX_TURNS●TTS/LIVE — 2.5-era audio and TTS previews shut down Nov 17, 38 days left●NEW — Deprecated with no shutdown date? Re-pick your image-model target with three conditions●3.8 FLASH — 3.7 Flash was deprecated on Oct 8. Requests to the old model are routed to 3.8 Flash automatically●NANO 2.1 — gemini-nano-banana-2.1 is GA. gemini-3.1-flash-image is deprecated with no shutdown date yet●DEADLINE — veo-3.1 previews and gemini-omni-flash-preview shut down Oct 22; the Deep Research agent follows Oct 23 (12-13 days left)●Q&A — Users report Gemini CLI marks a subagent run as a success even after it stops at MAX_TURNS●TTS/LIVE — 2.5-era audio and TTS previews shut down Nov 17, 38 days left●NEW — Deprecated with no shutdown date? Re-pick your image-model target with three conditions
Articles/Workspace
◧ Workspace/2026-06-29Advanced

Keeping Apps Script + Gemini Automations on Least Privilege: Explicit Scopes and Catching Scope Creep

Apps Script automations that call Gemini quietly accumulate OAuth scopes. Here is how to declare explicit scopes in appsscript.json, catch scope creep in CI, and avoid forcing every user to re-consent.

Apps Script12Gemini API247OAuthSecurity4Google Workspace21

✦ Premium Article

One morning I made a tiny edit to a Sheets automation that had been running quietly for about six months, redeployed it, and was met with a re-authorization screen. The line item read: "Read, compose, send, and permanently delete all your email from Gmail." All I had changed was appending one row to a sheet. I had not touched Gmail at all.

It asked for that permission anyway.

The reason was mundane. Months earlier I had called GmailApp once during a test, commented the line out, and forgotten to delete it. Apps Script statically scans your code and infers scopes from APIs that look used. A single line inside a comment was enough for it to request one of the broadest scopes available.

When you run several automations across Workspace as an indie developer, these auto-inferred scopes quietly swell over time. A script in production ends up holding read and write permissions it never actually needs. It is a dull but heavy liability: it widens the blast radius of any incident without you ever deciding to.

This article is about cutting that liability. Using a typical automation that spans Gmail, Sheets, and the Gemini API, we will declare the minimum scopes in appsscript.json, catch creep in CI, and avoid the re-consent accidents that scope changes cause.

Why auto-inferred scopes are dangerous

Apps Script has two ways to decide scopes. If you declare nothing, it infers them from your code. If you list them under oauthScopes in appsscript.json, inference stops and only the scopes you declared are requested.

Auto-inference is dangerous because three problems stack on top of each other.

ProblemWhat actually happens
It grabs oversized scopesA single GmailApp.search() pulls in "full read/write/delete of mail." You wanted read-only, but you now hold delete.
Dead code grants powerCalls left in comments or unreachable branches still feed inference. You request permissions you never exercise.
Change is invisibleNothing records who widened a permission or when. It never enters review, so creep goes unnoticed.

The principle of least privilege is that code holds only the permissions it needs right now. Auto-inference is fundamentally at odds with that.

The automation we will use

Let's work from a concrete setup, close to one I actually run:

  • Read unread mail under a specific Gmail label (never send, never delete)
  • Pass the body to the Gemini API to summarize and classify
  • Append the result to a single spreadsheet

The permissions this automation truly needs come down to three:

  1. Read Gmail, and nothing more (gmail.readonly)
  2. Read/write the one spreadsheet it is bound to (spreadsheets.currentonly)
  3. Outbound HTTP requests, to call the Gemini API (script.external_request)

No send permission. No Drive-wide permission. Left to inference, send and delete rights creep right in.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Step-by-step way to declare oauthScopes in appsscript.json and shut off the broad scopes Apps Script auto-assigns
✦A complete, copy-ready CI script that diffs declared scopes against an allowlist and fails on creep
✦How to roll out scope changes in stages so you never force every user into a surprise re-consent
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $15 for lifetime access
View Membership →

Related Articles

◧ Workspace2026-10-03
Estimating a Sheets-Driven Gemini Bill Across the Year-End Price Switch with Apps Script
If you call the Gemini API from a spreadsheet, log the token counts per call and estimate the month in two columns: the intro price that ends on December 31, 2026 and the standard price from January 1, 2027. Apps Script, with real output.
◧ Workspace2026-09-01
When a New Gemini Feature Hasn't Reached Your Workspace, Here's How to Tell Waiting From Broken
A step-by-step way to decide whether a missing Gemini feature in Google Workspace is still rolling out or actually misconfigured, using release tracks and rollout pace, plus a small Apps Script ledger that does the counting for you.
◧ Workspace2026-09-22
Workspace turned third-party connectors on by default. Two screens to check before you decide
Since September 15, 2026, Gemini in Workspace connects to Asana, Salesforce and five other tools over MCP, and the setting ships on by default. Here is how I count what is actually enabled, from both the Admin console and the user side panel.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links