In short: Ad accounts are not hacked by guessing the password. The documented ways in are a stolen browser session, a phishing proxy that relays the password and the one-time code, a fake manager-link or partner request, a stolen API token, and access that was never revoked. At Lynt we therefore run a check every 30 minutes on every client's Google Ads and Meta account: is the account still active, did the payment method or spending limit change, do the ads still point at the client's domain, did anyone new get access. Every change goes to Slack and to an internal page where the responsible person approves or rejects it. The implementation brief is available as a download.
Attackers do not guess Google Ads or Facebook ad account passwords. Security reports from 2025 and 2026 describe five ways in, and a password is the weak point in none of them.
- A stolen browser session. Infostealer malware copies cookies from a logged-in browser. Recorded Future indexed 276 million credentials with a live session cookie in 2025. A cookie requires no password and no second factor (Recorded Future). Attackers deliver Ducktail, a malware family written for Facebook Business accounts, as fake marketing job offers (WithSecure).
- A phishing proxy that passes the two-factor check. The victim types the real password into what looks like the real page and approves the prompt. The proxy then keeps the session the real site creates. By mid-2025 a single rented phishing kit was behind 62 percent of the phishing attempts Microsoft blocked (Microsoft). Criminals have bought Google Search ads for the query “Google Ads” to send victims to such a proxy (Malwarebytes).
- A fake invitation. On Meta, the attacker files a partner request. The lure sits in the business name, while the e-mail itself is a genuine message from Meta (Huntress). On Google, the attacker sends a fake manager-account invitation that leads the victim to a look-alike login page. Agencies lost entire manager accounts this way with two-factor switched on (Search Engine Land).
- A stolen API token or app grant. OAuth grants and Meta system-user tokens keep working after a password reset until an administrator revokes them.
- Access nobody revoked. The freelancer from two years ago, the previous agency, the client’s former marketing manager.
Once inside, the attacker adds an admin and links a parent account. Then they change the payment method or the spending limit, launch campaigns and point the ads at a domain that is not the client’s. Mimecast counted 1.86 million ad-account-theft detections in the second half of 2025 alone. A stolen account sells for a few hundred dollars (Mimecast). In the published cases the agencies discovered the theft themselves, often the next morning.
Why we built a 30-minute check
We manage client accounts on Google Ads and Meta. Our earlier check ran every 2.5 hours and looked only at user access. In the published cases the money was gone within a day, and access is only one of the things that change in a taken-over account. The check now runs every 30 minutes and covers more: account status, payment method, spending limit, ad destinations and user access.
This version went live in September 2026. It reads every managed account on both platforms every 30 minutes. The list of who has access on Google is read even more often, every 18 minutes. Once a day the monitor also re-reads every account in full, covering the data the 30-minute runs do not touch. The software changes nothing in either platform. A human makes the decisions.
What it checks
| Check | Google Ads | Meta |
|---|---|---|
| Is the account active? | Account status read through our manager account. States include suspended, cancelled or closed. The API gives no reason for a suspension, and the alert states that limitation. | Account status and disable reason. This includes Meta's own compromised flag. |
| Is there a payment problem? | Account budget exhausted on invoiced accounts. The API exposes neither a card decline nor a prepaid balance. The alert states this limitation. | Funding source changed. Spending limit changed or reset. Account marked unsettled for an unpaid balance. |
| Do the ads still point at the client's domain? | Change events plus today's landing-page report every 30 minutes. The check re-reads modified items. A daily pass covers configured URLs and tracking templates on every level. | Links inside every active creative every 30 minutes. A full audit runs daily. It catches any change to URL parameters. |
| Did anyone new get access? | Every user with role, creation date and the person who invited them. Pending invitations. Manager links in every status. A pending request is seen before the client accepts. We scan our own manager accounts the same way. | The activity log shows which users were added to or removed from the account. Partner businesses added or removed. Daily checks cover our own Business Manager users, system users and two-factor settings. |
| Did we lose our own access? | An account that stops responding is marked unreadable until it responds again. | A lost grant triggers an alert. An invalid token fails the run and reports the failure. |
The system compares every read with the previous snapshot. Every added, removed or changed row becomes a finding. A permission error is stored as its own state per account, never as an empty result. The daily summary turns red when a check has not run within its scheduled interval.
How the team works with it
- Related findings on one account merge into one incident. The incident is sent to Slack as a direct message to the reviewer and posted as one record in the team channel. The message and the record both name the client and the specialist who looks after the account, in two lines with a link. Alerts do not repeat unless the incident escalates.
- The link opens an internal page reachable only inside our network. It shows the account, what changed, the previous and the new state, when we saw it and what to verify.
- Approving an event records the exact scope. The approval names exactly what was allowed, for example a particular user with a particular role, or a particular domain on a particular account. A later change requires a new review. Rejecting an event keeps the incident open as unauthorised. When a fresh read can neither confirm nor refute an event, the reviewer closes it with “Resolve with a note”.
- A human fixes the problem in Google Ads or Meta. The incident closes when the next complete read confirms the removal of the unauthorised state.
- The status page lists the specialist for every account. It shows the last successful read, pending decisions and the data we cannot read. One two-line summary for both platforms goes to Slack at 07:00.
Why these choices
- Every 30 minutes. The API quota sets that interval. Every read and the consumption of our other tools count against the same quota. The monitor counts its own operations against that limit and reports any late run.
- Read-only with human approval. A new user or a new domain is often a specialist’s change or the client’s new agency, and it can just as well be a takeover. The monitor cannot tell them apart. The responsible person can, usually within the hour.
- Failures are never hidden. A monitor that dies quietly is worse than none, because it makes the team stop looking. An expired token fails the run and reports the failure. A permission error is stored as a state of its own, never as an empty result. An account that cannot be read is flagged as not read every day.
- Limits on every alert. Green must never mean “we can’t see it”. Shopping product URLs live in Merchant Center, not in the Ads API. Dynamic Search Ads pick their landing page at serve time. In our own scan, four in ten active Meta ads had their link stored in a Page post, and catalog ads store theirs in the catalog. Reading Page posts or the catalog needs permissions our app does not hold. Google does not expose card declines. The two-factor status of client users remains unreadable on either platform. We enforce two-factor in the account settings instead.
Download the checklist and the implementation brief
One file. A security checklist to review with the people who administer your Google Ads and Meta accounts, and an implementation brief for the monitor above: sample Google Ads API v23 queries, Meta API v24 reads, proposed detection rules and the known coverage gaps. An implementer must adapt and test it for your accounts. Leave your email and the file is yours.
One file, one list. I only write when there's something worth reading.
My Google Ads account was hacked. What do I do first?
Use a trusted device and isolate any computer you suspect is infected. Report the compromise to Google Ads through its compromised-account form right away. If you can still open the account, pause unauthorised campaigns, keep the change history and billing pages as evidence, and remove confirmed unauthorised users and manager links under Access and security. If you are locked out, start Google Account recovery. Reset the password, review signed-in devices and revoke third-party access you do not recognise. Check the recovery e-mail and phone and the payment methods, and report unauthorised charges to your card issuer.
How do I know if my Facebook ad account or Business Manager was hacked?
Investigate any unfamiliar user or partner, any removal of an admin you did not order, any funding change and any campaign you did not authorise. One of them is enough to act; do not wait for a full sequence or for Meta’s compromised flag. Secure the compromised Facebook account through Facebook’s hacked-account recovery and contact Meta business support about the affected assets. If you still have access, pause unauthorised ads and remove confirmed unauthorised access. Ask the business administrator to review integrations and revoke affected system-user tokens.
Why did two-factor authentication not stop it?
A stolen session lets an attacker act without another login, so no second factor is requested. A phishing proxy relays your password and one-time code to the real site and keeps the session the real site creates. Passkeys and hardware security keys resist that form of phishing, but they cannot protect a session already stolen from an infected device. Approving an attacker’s access request is a separate failure: you authorised them.
Can the Google Ads and Meta APIs report users' two-factor status?
Google Ads API v23 exposes neither per-user 2-Step Verification status nor the account-level requirement. Meta exposes two-factor fields for a business you are authorised to administer. In our partner-access test, the API response for a client’s business lacked those fields and returned an empty user list. Treat a missing field as unknown, not as disabled, and verify client requirements in the settings.
How often should an agency check who has access to client ad accounts?
Choose the interval by potential spend, access risk and how fast someone can respond. Published takeovers burned tens of thousands of dollars within a day, so a nightly check leaves a long window on a high-spend account. We poll every client account every 30 minutes. A weekly or quarterly access review is an offboarding check. It does not detect a takeover in progress, so use the platforms’ security and billing notifications between reviews.
Does polling every 30 minutes blow the Google Ads API quota?
A small portfolio does not come close to the limit. The sums below assume every read runs every 30 minutes. At a 30-minute interval, each of the four access reads runs 48 times a day. With seven daily destination reads and a change-event read every 30 minutes that is 247 operations per account per day before targeted re-reads, retries and any other tool. Basic access allows 15,000 operations per sliding 24 hours. At 247 operations per account that covers at most 60 accounts. A larger portfolio needs a longer interval or Standard access. Check the access level of your Google Cloud project and reserve capacity for the whole workload.
Start with one account. Verify its user roster and its approved destinations by hand, then test detection, a failed read and alert delivery before you expand the monitor to the rest.