What it does
TATER Tuning is a per device-group, per app, dial-based hardening surface. Instead of authoring one-off PowerShell hardening scripts (or worse, copying CIS Benchmark policies by hand), you set a level 0–10 for each (group × app) cell, and the TATER Agent enforces it on every device in that group within 30 minutes.
Live at TATER Security → Security → TATER Tuning.
How the matrix works
Two axes:
- Device Groups — named cohorts (Beta Testers, Phase 1, All Devices, …) with a list of hostnames. A device can be in multiple groups; it inherits the highest level for each app across all the groups it belongs to.
- Apps — Chrome, Edge, Defender, Office, Windows, UX. Each app axis is independent: you can run Chrome at level 3 while keeping Defender at level 1.
Each cell shows the current level and a color heat-map:
| Level | Color | Posture |
|---|---|---|
| 0 | grey | Off — no enforcement, just visibility |
| 1 | green | Baseline — telemetry trimmed, Windows audit policy |
| 2 | green | Browser Safer — SmartScreen strict, niche APIs blocked |
| 3 | green | Defender Audit — ASR + Network Protection logging |
| 4 | amber | Defender Enforce — ASR rules in BLOCK mode |
| 5 | amber | Office Macro Lockdown — block macros from internet |
| 6 | amber | Removable Media + Network — USB executables, LLMNR/NBT/NTLMv1 |
| 7 | red | Application Control — AppLocker / WDAC audit then enforce |
| 8 | red | Constrained Scripting — PowerShell CLM |
| 9 | red | Workstation Lockdown — short screen lock, smart-card preferred |
| 10 | red | Fortress — removable media off, BitLocker pre-boot PIN |
Not every level has content defined for every app yet — the dial cap per app is shown next to the cell (L2 / 3 means level 2 of a 3-defined max). Each level inherits the previous and adds curated controls.
The "All Devices" group
TATER seeds a built-in All Devices group per organization on first load of the Tuning page. It carries an autoIncludeAllHosts flag, so every agent in the org inherits its levels automatically — no admin maintenance of a hostname list, no risk that a newly-enrolled laptop misses the baseline.
- Always sorted to the top of the matrix.
- Undeletable — guards against accidental removal of the org-wide floor.
- Name is locked (cannot be renamed), but levels and overrides on it are fully editable.
- Combined with the highest-level-wins rule: set Chrome L2 here for everyone, then add a narrower "Privileged Admins" group that overrides to Chrome L4. Admins get L4; everyone else gets L2.
The Tuning column on Manage → Devices
TATER Manage's Devices table renders a compact per-device hardening snapshot in a Tuning column. One letter+number per app, separated by spaces:
| Letter | App |
|---|---|
C | Chrome |
E | Edge |
D | Defender |
O | Office |
W | Windows |
U | UX |
Example: C2 E2 D3 W3 means Chrome L2 / Edge L2 / Defender L3 / Windows L3 (Office + UX not set on this device).
If any app's last enforcement run reported drift (Tamper Protection blocked a registry write, an ACL refused, etc.), that letter flips red with a ! suffix. Hover for the tooltip — the failing control names are listed there. Click the cell to open the Drift Triage modal (see below).
Self-healing on drift
TATER Tuning doesn't just see drift — it acts on it. Two automatic behaviors close the loop, both gated by a 3-consecutive-cycles rule to suppress one-off transient noise:
| Scenario | What happens |
|---|---|
| Same control drifts for 3+ consecutive cycles | API auto-opens a MonitoringFinding of source=hardening. Severity follows the app: Defender + Windows = High · Chrome / Edge / Office = Medium · UX = Low. Surfaces in TATER Ops → Application Monitoring just like KEV and OneDrive findings. |
| Drift stops (control finally takes, or you accept risk) | The open finding is auto-resolved on the next state-report cycle. The driftHistory entry is dropped from the device state. |
| Drift bounces in and out (single-cycle blips) | Nothing happens. The cycle counter never reaches 3 → no finding gets created. |
The threshold of 3 cycles ≈ 1.5h at the default 30-min hardening poll interval. Adjust the poll interval in the agent config if you want signals to surface sooner or later.
Accepting drift as risk from the Devices view
Clicking a red app letter on the Manage Devices Tuning column opens the Drift Triage modal. It lists every drifted control on that device with a per-row Accept risk button.
Accepting risk:
- Prompts you for a reason (minimum 5 chars — surfaces in the audit log and the override list).
- POSTs to
/api/hardening-state/{hostname}/ack-drift. - The API appends the control to the org's "All Devices" HardeningProfile for the relevant app (or a custom group if you supply one in the body).
- Recomputes the profile's
contentHash, so the agent picks up the new override on its next poll. - On the next agent cycle the control falls out of
driftPerApp; the open MonitoringFinding auto-resolves the cycle after that.
Use this when drift is a documented carve-out you don't intend to fix (incognito mode for the privacy team, USB allowed for the design team). Use the regular Tuning matrix workflow (lower the level OR write a more permissive override on a narrower group) when you want to fix or escalate the drift instead.
Risk-accept overrides
The single most important feature: per cell, you can list individual CIS controls to skip with a documented reason. Use this when an org needs a specific carve-out — e.g. you set Chrome to level 3 but accept the risk of NOT disabling Incognito mode for your privacy review team.
To add an override: open a cell, type the control id (CHR_128), the business reason, optionally an expiry date. The agent skips that control when it applies the level; everything else still runs.
How agents enforce it
The Go agent v2.4.25+ spawns a hardening goroutine in both service and tray modes. Every 30 minutes (and once at startup), the agent:
- GETs
/api/agents/{hostname}/hardening-target?includeBodies=1— returns the merged target for this device (highest level per app across all its groups, plus the union of overrides, plus the actual script bodies to run). - Compares the per-app
contentHashagainst the locally-cached applied hash (kept in%ProgramData%\TATER\hardening-state.json). - For each app where the hash differs: writes each script body to a temp
.ps1and runs it as SYSTEM withpowershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File(the same pattern the scanner uses for CIS control checks). 10-minute per-script timeout. - On success, updates the local state file and POSTs the new applied levels + hashes back to
/api/agents/{hostname}/hardening-stateso the Manage fleet view stays current.
If the device isn't in any group with a profile, the loop is a silent no-op — safe to roll fleet-wide with no per-device configuration. If the API returns an error (org hasn't enabled TATER Tuning at all), the agent silently skips the cycle and tries again later.
The level registry
The mapping from (app, level) to actual OpsScript bodies lives in api/src/functions/taterTuning.ts as LEVEL_REGISTRY. Today's seed levels (1-3 per app) point at the three hardening scripts shipped on 2026-06-08:
CB-LowImpact-Hardening-Win-Edge-Chrome— 43 baseline registry policiesCB-LowImpact-BrowserPolicy-Mega— 138 Chrome/Edge safe-default policiesCB-LowImpact-BrowserPolicy-GapFill-v2— 36 more viareg.exepathCB-LowImpact-Hardening-Batch2— Defender + DEP/SEHOP in AUDITCB-Aggressive-Win-Hardening-Phase3— Audit policy + Defender BLOCK + Office macros + NTLM/NetBIOS
Adding more levels (4-10) is a single-PR change to LEVEL_REGISTRY — author a new OpsScript, append its id to the right cell, no schema migration.
MCP tools
Three tools mirror the API. Both HTTP and stdio MCP servers expose them.
| Tool | Auth | Notes |
|---|---|---|
list_device_groups | Viewer | Names + member counts. |
set_hardening_level | Admin (write) | Set a (groupId, appKey, level) cell. Returns the new contentHash. |
accept_hardening_risk | Admin (write) | Add a per-control risk-accept on a cell. Reason + optional expiry. |
Example AI prompts:
- "Move Beta Testers Chrome to level 3 and accept risk on CHR_128 because privacy review needs incognito."
- "What groups do we have and what's their current Defender posture?"
- "Push everyone except the dev team to level 2 on Office macros."
API surface
| Method | Path | Purpose |
|---|---|---|
| GET | /api/device-groups | List groups. |
| POST | /api/device-groups | Create a group. |
| PUT | /api/device-groups/{id} | Rename or change hostname list. |
| GET | /api/hardening-profiles | List all (group × app) cells. |
| PUT | /api/hardening-profiles/{groupId}/{appKey} | Set the dial + overrides for one cell. |
| GET | /api/hardening-registry | What each (app, level) means. |
| GET | /api/hardening-state | Fleet view of applied levels. |
| GET | /api/agents/{hostname}/hardening-target | Agent reads its merged target. ?includeBodies=1 for actual script bodies. |
| POST | /api/agents/{hostname}/hardening-state | Agent reports applied state. |
Operational tips
- Always start with a Beta group of one machine (yours). Crank that to your target level, live with it for a week, then add Phase 1 and Phase 2.
- Browser policies take effect on browser restart. The scanner may flag affected controls as "Manual" between the apply and the browser relaunch.
- Risk-accept early. If your team relies on a quirky workflow (extensions, Cast, sync), accept the relevant CIS control IDs up front rather than skipping a whole level.
- Rollback is one script away. Every script writes a JSON log to
%ProgramData%\TATER\hardening-logs\. The companionCB-Hardening-Rollback-FromLogscript reverses any single batch.
Roadmap
- Drift detection — agent compares actual registry state to expected and reports specific control IDs that drifted. Manage fleet view will surface this as a per-device drift count.
- Levels 4–10 content — adding OpsScript payloads for AppLocker, PowerShell Constrained Language Mode, BitLocker pre-boot PIN, removable-media policy, etc.
- Per-app status pills — show on the Devices page so a technician can answer "is this machine compliant with its assigned tuning?" without opening the matrix.