mcc-hack-audit
Skill72 starsChanged 4 months agoMITView on GitHub
Portfolio-wide scan of every manager (MCC) that has access to accounts in your Google Ads tree. Built after an MCC link-fraud incident where hostile external MCCs were found linked to client accounts via compromised admin credentials. Classifies each manager link as INTERNAL (in your tree), HOSTILE (known threat), or EXTERNAL (potential exposure — no judgment). Outputs CSV by default with optional Google Sheets upload. Auto-invoke when user says 'mcc hack audit', 'audit mcc links', 'scan for external managers', 'check manager links', 'run mcc link scan', 'find external mccs', or asks who has access to their Google Ads accounts.
In this repository41 other files it gives its agents.
- account-diagnosticSkill
- ad-copy-generation-frameworkSkill
- ad-copy-verification-standardSkill
- add-account-negative-keywordsSkill
- ads-checkerSkill
- budget-guardianSkill
- budget-recommendation-calculatorSkill
- change-history-checkerSkill
- client-communication-standardsSkill
- competitor-analysis-v2Skill
- conversion-tracking-healthSkill
- dgen-automation-disableSkill
- fair-housing-complianceSkill
- ga4-campaign-cross-referenceSkill
- ga4-cross-analysisSkill
- ga4-lead-quality-investigationSkill
- gaql-query-patternsSkill
- geo-conflict-analyzerSkill
- google-ads-api-setupSkill
- google-ads-querySkill
- google-ads-samplesSkill
- impression-share-diagnosticsSkill
- investigation-methodologySkill
- lead-quality-pattern-analysisSkill
- lead-quality-recommendation-prioritizationSkill
- markdown-to-sheets-presenterSkill
- mutation-safetySkill
- neg-conflict-finderSkill
- non-serving-keyword-scannerSkill
- pmax-asset-automationSkill
- pmax-builderSkill
- portfolio-health-prioritizationSkill
- portfolio-pacing-rulesSkill
- rsa-bulk-editSkill
- rsa-refreshSkill
- rsa-single-accountSkill
- shared-budget-updaterSkill
- sqr-classifierSkill
- sqr-pipelineSkill
- underspending-investigationSkill
- youtube-placement-auditSkill
The file
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 3 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 24
Every account under your login_customer_id (walks customer_client) — including your root MCC itself
- Very specific: line 26
Every manager-link relationship on each account (customer_manager_link) — all link statuses, not just active ones: a REFUSED or CANCELED …
- Distinctive: line 30
All account statuses (ENABLED, CANCELED, SUSPENDED, CLOSED) — security-relevant data lives in canceled accounts too
- Very specific: line 32
Output: every (account, manager) pair, plus a suspicious-only subset (HOSTILE + EXTERNAL).
- Distinctive: line 48
Every non-internal manager is EXTERNAL — even an agency you've worked with for 10 years, even an MCC that's been linked since the account …
- Very specific: line 52
If you'd rather not see long-standing trusted MCCs in the suspicious list, --trusted-cids classifies them TRUSTED instead — but that …
- Very specific: line 116
Start empty. Populate as incidents occur — the escalation path in rules.md tells you when a CID earns an entry, and its "Sharing …
- Distinctive: line 127
Check every surprise against the false-alarm table before escalating.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
MCC Hack Audit
Owns one workflow: walk your entire Google Ads tree and map every manager (MCC) with a link into it — then hand the operator a triage-ready answer to "which MCCs currently have access to which of my accounts, and which are outside my own tree?" Built after a real-world MCC link-fraud incident where hostile external MCCs gained access to client accounts via compromised client-side admin credentials.
The triage judgment — which links matter, when a finding becomes an incident,
what "trusted" costs — is rules.md. The exact
walk/classification/output mechanics and the hard-won API limitations are
references/scan-contract.md.
What It Scans
Included:
- Every account under your
login_customer_id(walkscustomer_client) — including your root MCC itself - Every manager-link relationship on each account
(
customer_manager_link) — all link statuses, not just active ones: a REFUSED or CANCELED link is an attempt record, and attempt records are security data - All account statuses (ENABLED, CANCELED, SUSPENDED, CLOSED) — security-relevant data lives in canceled accounts too
Output: every (account, manager) pair, plus a suspicious-only subset
(HOSTILE + EXTERNAL). Full column layout, sort orders, and the Sheets-tab
contract: references/scan-contract.md.
Classification Model — No Judgment
Three classifications, defined by objective ownership only (precedence mechanics in the contract):
| Class | Definition |
INTERNAL | manager_cid is inside your own MCC tree (auto-detected by walking customer_client) |
HOSTILE | manager_cid matches an entry in your hostile-MCC list (you populate this) |
EXTERNAL | Anything else. Potential exposure point regardless of name/age/footprint. Never auto-classified as legitimate. |
Critical: There is no "allowlist" or "trusted partner" concept by design. Every non-internal manager is EXTERNAL — even an agency you've worked with for 10 years, even an MCC that's been linked since the account was created. The point is identification, not pre-clearance. You judge.
If you'd rather not see long-standing trusted MCCs in the suspicious list,
--trusted-cids classifies them TRUSTED instead — but that suppresses
visibility, not attack surface (rules invariant: re-audit trusted CIDs on
the same cadence).
Deliberately does NOT do
- No link removal — revocation is a manual UI action, by design.
- No outreach — no client emails, no Slack, no notifications. All communication is your call.
- No auto-judgment — nothing is ever classified "legitimate"; EXTERNAL stays EXTERNAL until you verdict it.
- No watchdog mode — manual runs only; the cross-day CSV diff is the
manual watchdog pattern (
rules.md, cadence). - No name resolution for external CIDs — the API refuses it (contract, limitation 1); naming happens in the UI's Account Access page.
- Single parent MCC per run — the script reads one
login_customer_idfrom your YAML; multiple parent MCCs = one run each.
Prerequisites
- Google Ads API credentials YAML with MCC access (
google-ads.yaml) — see the google-ads-api-setup skill if you don't have one - Your
login_customer_idset in the YAML — the script auto-detects your tree from this - Python packages:
google-ads,pyyaml - Optional:
gspreadif you want Sheets upload — auth isgspread.service_account(): service-account JSON at gspread's default location (~/.config/gspread/service_account.json), target sheet shared with the service account's email; or adaptmaybe_upload_to_sheets()to reuse thegoogle-ads.yamlOAuth credentials like this repo's other Sheets-writing skills
How to Run
# Default: walks your full tree, writes CSVs to output/
python scripts/mcc_hack_audit.py
# Custom output directory
python scripts/mcc_hack_audit.py --output-dir my-audit-output
# Include Google Sheets upload (requires gspread auth)
python scripts/mcc_hack_audit.py --sheet-id YOUR_SHEET_ID
# Add known-hostile CIDs from a JSON file
python scripts/mcc_hack_audit.py --hostile-list hostile.json
# Mark specific external CIDs as trusted (they'll be classified TRUSTED instead of EXTERNAL)
python scripts/mcc_hack_audit.py --trusted-cids "1234567890,0987654321"
# Tune parallelism (default 20, lower if you hit RESOURCE_EXHAUSTED)
python scripts/mcc_hack_audit.py --workers 10
# Custom credentials path
python scripts/mcc_hack_audit.py --config /path/to/google-ads.yamlRuntime: ~2-5 min for a 1,000-account tree at 20 workers. Plan ~10 min for a 10,000-account tree.
Hostile list format (hostile.json) — CID → one-line context (the
authoritative shape lives in the contract; this is the run surface):
{
"1234567890": "label or context for this hostile MCC",
"0987654321": "another known-bad CID with a one-line note"
}Start empty. Populate as incidents occur — the escalation path in
rules.md tells you when a CID earns an entry, and its
"Sharing hostile-MCC intelligence" section covers when (and when not) to
publish entries beyond your own list.
After a Run (status leg)
Open output/mcc_link_scan_YYYYMMDD_SUSPICIOUS.csv and walk the triage
order in rules.md: HOSTILE rows, then PENDING-to-unknown, then
EXTERNAL newest-first, then the attempt records. Datestamped CSVs accumulate
across days — diff the newest two to see link churn (the manual watchdog).
Check every surprise against the false-alarm table before escalating; the
error count vs your canceled-account inventory is the standing coverage
check.
Files in this skill
| File | Role |
SKILL.md | This file — workflow + routing |
rules.md | Judgment: triage order, escalation default, cadence, threat-intel sharing, false alarms |
examples.md | Three worked reads (clean baseline, the PENDING invite incident, the absent account) |
references/scan-contract.md | Exact walk/classification/output mechanics + API limitations |
scripts/mcc_hack_audit.py | The parallel tree-scan engine |
Runtime artifacts (never committed): output/*.csv scans, your
hostile.json, your google-ads.yaml.
When to load sibling skills
| Load | When |
change-history-checker | A link needs the activity question answered — "what changed after this manager appeared?" This skill maps who has access; that one reads what changed (and inside 30 days, who changed it) |
mutation-safety | Any change you make in response to findings — remediation actions go through its approval discipline |
google-ads-api-setup | First run, or any credentials error |
gaql-query-patterns | Writing follow-up queries beyond what the scan and the history checker ship |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

