# 59 Config-drift & persistence sentinel (incl. mail-routing watch)

> v0.1.2 · role: Detect · [policy: #27 · #12, #33, #34](https://docs.google.com/spreadsheets/d/1nOztaPd1Y7eNeRSR_hdovYy-ncpx-bAx/edit?usp=sharing&ouid=115159875779023172526&rtpof=true&sd=true)

A scheduled job snapshots the settings an attacker changes in order to persist — admin role assignments, domain-wide delegation clients and their scopes, the OAuth allowlist, Gmail routing rules, mail hosts and compliance rules, forwarding, 2SV enforcement — and diffs each run against the last approved baseline. A silent inbound or outbound routing rule is the classic post-compromise persistence, and it is invisible to the user whose mail it copies.

## Caveats

- The sentinel must run under an identity the attacker cannot silence — a super-admin snapshotter is disabled by the same compromise it is supposed to detect.
- Alerting on every diff without a change-approval feed produces pure noise — and noise is what gets the sentinel muted, so the control is the unapproved-delta alert, not the diff.

## Setup steps

1. Write a scheduled snapshotter (Apps Script or GAM in CI) that dumps the persistence-relevant config every run: admin role assignments, domain-wide delegation (DWD) clients, OAuth app allowlist, Gmail routing/forwarding rules, mail hosts, 2SV enforcement.

   - **Cadence** = hourly for routing/DWD, daily for the rest

2. Include the Gmail Routing and Hosts tables in the snapshot (Hosts is its own screen under Gmail > Hosts) — a silent inbound/outbound routing rule is the classic post-compromise persistence. — `Apps › Google Workspace › Gmail › Routing`

   ```
   Diff on any add/change to routing, hosts, or compliance rules
   ```

   docs: [Add Gmail routing settings](https://knowledge.workspace.google.com/admin/gmail/advanced/add-gmail-routing-settings) · [Add mail servers for Gmail email routing](https://knowledge.workspace.google.com/admin/gmail/advanced/add-mail-servers-for-gmail-email-routing)

3. Snapshot the DWD client list + scopes; any new client id is an alert. — `Security › Access and data control › API controls › Manage Domain Wide Delegation`

   - **Any new client id or scope** = High severity

   docs: [Control API access with domain-wide delegation](https://knowledge.workspace.google.com/admin/apps/control-api-access-with-domain-wide-delegation)

4. Diff each run against the last committed baseline and alert on any delta not preceded by an approved change.

   - **Unapproved delta** = page
   - **approved delta** = auto-commit new baseline

## Ongoing maintenance

- **[automatable: script]** Per schedule: the sentinel run itself.
- **[automatable: AI agent]** Per run: read the diff and separate deliberate change from drift or persistence.

## How to verify

1. Check the sentinel’s last run is within its schedule, then change a benign monitored setting and confirm the next run flags it. Revert the setting.

## Settings screens

- Apps > Google Workspace > Gmail > Routing
  - console: https://admin.google.com/ac/apps/gmail/routing
  - screenshot: ../screenshots/admin.google.com/ac/apps/gmail/routing.png
- Security > Access and data control > API controls > Manage Domain Wide Delegation
  - console: https://admin.google.com/ac/owl/domainwidedelegation
  - screenshot: ../screenshots/admin.google.com/ac/owl/domainwidedelegation.png
- Account > Admin roles
  - console: https://admin.google.com/ac/list/roles
  - screenshot: ../screenshots/admin.google.com/ac/list/roles.png
