Preserve evidence before it decays
Logs roll off, exports expire, access gets reassigned during remediation. Every day between the incident and the investigation is a line of inquiry quietly closing. I lost at least one this way, more on that below.
A digital-marketing agency hired me to document a Google Ads account takeover that had already been cleaned up. They’d run a couple of off-the-shelf scans and settled on a theory, but no one had actually investigated because no one had been hired to. Before I could write a credible report, I had to reconstruct the attack myself…from incomplete evidence that trickled in over a week, that contradicted itself, that twice pointed me at the wrong conclusion, and that eventually pointed back at my own client’s house.
The job came through Upwork and on paper it was simple: a U.S. digital-marketing agency that had recently acquired a second agency needed a formal, client-facing cybersecurity incident report. One of their managed Google Ads accounts had been taken over by an attacker, run up a mountain of fraudulent campaigns, and then recovered. The remediation (in which Google had been involved) was finished and the fire was out.
What they wanted from me was the write-up: a polished, professional document they could hand to the end-client to explain what had happened and reassure them it was contained, so documentation and analysis of materials they already had which was, “Essentially, just write it up.”
That framing is worth pausing on because it’s the entire story. A “write it up” engagement assumes the it exists…that someone has already done the investigation and reached defensible conclusions, and that my job is to dress those conclusions in clean prose and a confident tier list. That’s a legitimate kind of work, and I’ve done it.
This however was not that.
This is the distinction the whole engagement turned on so it’s worth being precise about it. The client wasn’t lazy and they weren’t hiding anything as they had genuinely collected materials: two Google Ads change-history exports, a third-party dark-web exposure report on the domain, a DNS and email-authentication check, and a working hunch that some of their employees’ credentials might have been stolen. That’s what “documentation and analysis of materials they already had” meant. From their side, it felt like the hard part was finished and all that remained was the writing.
But a pile of scans is not an investigation and the difference is the entire job. An exposure report tells you credentials exist on the dark web but it doesn’t tell you they were used, by whom, or against what. A DNS check tells you your email authentication is misconfigured but it says nothing about how an attacker got into an ad account. These are inputs (useful ones) but each is a flashlight pointed at one corner of the room. An investigation is what happens when someone stands in the middle of that room, in the dark, and reconstructs what actually moved through it: a timeline, built from primary evidence, that separates what is known from what is merely plausible.
The client had skipped straight to plausible: their theory had a villain (the previous owner of the agency they’d acquired, supposedly acting on leftover access) with a garnish of generic “dark-web exposure” to cover whatever the villain didn’t. It was a clean story but it was also, as far as the evidence went, unsupported. Nobody had reconstructed the attack from the change history or pulled the login or OAuth logs where the answer actually lived or separated confirmed fact from assumption. And that unverified theory had already been written into the agency’s communications to their end-client. A guess had quietly become the official account before anyone checked it.
Cleanup ends the visible symptom. The postmortem is where the cause, the evidence, and the durable fix are separated from the story everyone wants to believe. When something bad happens, the temptation is to do exactly what this client did: clean up the mess, settle on the most comfortable explanation, and move on. A real post-incident review resists that and it pays for itself in concrete ways.
Logs roll off, exports expire, access gets reassigned during remediation. Every day between the incident and the investigation is a line of inquiry quietly closing. I lost at least one this way, more on that below.
The first plausible theory is the one most likely to be wrong precisely because it was chosen for being comfortable rather than for being tested. Here, the first theory blamed a specific, named person whom the logs later cleared completely.
The exposure report rated the domain "high risk." That's a reason to look but it's far from a conclusion. Treating "exposure exists" as "this was the vector" is how an investigation lands on a plausible cause while missing the real one.
Deleting the attacker's campaigns ends the symptom. Finding why they got in, whether through a forgotten account or a shared second factor, is what stops the next one. The most valuable output of this engagement was a fixable process failure nobody had named.
The goal shouldn't be to find a person to fault but rather find the failed process. That framing mattered double here because the evidence was about to point back at my own client's house, and a review that's hunting for a culprit instead of a cause can't survive that turn.
So I made the choice the engagement had quietly assumed someone else already had: instead of dressing up the client’s theory in confident prose I started the investigation. I told the client what I was seeing, and I began parsing logs.
Google Ads change history is a transaction ledger: every budget edit, every user invitation, every account link, stamped with a timestamp and the account that performed it. If you read it carefully, an account takeover writes its own confession.
Pulling the anomalous activity out of the normal baseline, the shape of the attack came into focus:
cluster detected: attacker-controlled accounts, not a lone actor; one lead account did the structural damage while a swarm of operator accounts did the volume.
two waves: initial takeover, partial cleanup by the legitimate team, then a re-compromise a month later that immediately showed the first remediation had missed something.
privilege change: legitimate administrators demoted to reports-only access inside their own account.
external manager link: the advertising account was secretly linked to an attacker-controlled manager account, letting control be siphoned away from the owner.
campaign flood: roughly 170 fraudulent campaigns spun up while the account was quietly renamed out of the client's branding and into the attacker's naming convention.
That last detail mattered more than it looked. The new name matched a recognizable pattern…the same convention stamped on a whole standing roster of other accounts the attacker operated, some dating back years. This wasn’t a smash-and-grab against one coworking brand, but rather it seemed the account had been absorbed into a pre-existing, ongoing advertising-fraud operation and the access records hinted the brand was probably not the only client pulled in.
The impressions data put a number on the damage: normal activity for this account ran a few hundred ad impressions on an active day, but at the peak of the second wave it hit over 400,000 in a single day which was roughly six hundred times baseline.
This was already a different document than the one I’d been hired to write, but…I still didn’t know how the attacker got in and I was about to spend time being wrong about it twice.
Real investigations rarely arrive as a tidy folder. The supporting materials came as a slow drip (exposure reports, then a domain check, then the contract, then internal emails) each piece reshaping the picture, several of them forcing me to walk back something I’d already concluded.
And the evidence kept fighting me on its own reliability:
An export whose date range lied. One file’s header claimed several months of coverage but its earliest actual row was the morning of the attack. If I’d trusted the header, I’d have reported “no suspicious activity before the incident” when the truth was “this export simply doesn’t contain the earlier period.”
A 12-megabyte CSV that wouldn’t open. The attacker’s bulk actions had produced individual cells so large they exceeded the spreadsheet’s per-cell limit and the file physically would not load. I had to build a spreadsheet-safe version before I could read my own evidence.
A log that structurally couldn’t answer the question. Change history records changes, not logins, and it doesn’t record actions taken through the API. The “who was signed in, from where, and how” questions (the identity layer) lived in an entirely different set of logs and those weren’t in the drip.
I flagged each of these to the client as I hit them. This is the unglamorous core of the work: a conclusion is only as trustworthy as the export under it and a surprising number of exports don’t say what they claim to.
That last gap is what changed how I worked. The identity-layer logs were the ones that would actually answer the question and waiting on them to be exported and emailed to me, one request at a time, was going to take longer than the client had patience for as he wanted the report yesterday. So rather than keep volleying requests back and forth, I asked for direct access to the Workspace environment and offered to pull what I needed myself.
That ran straight into a small irony. I could enter the password for the account credentials he shared, but the sign-in died on a wall: “Your sign-in settings don’t meet your organization’s 2-Step Verification policy.” The organization had hardened its 2-Step Verification during the very incident I was investigating and that fresh enforcement now refused to let the investigator in. We solved it the clean way, which happened to be the secure way: rather than bolt loose external access onto a policy that was correctly rejecting it, the owner created me my own in-domain admin account. With that, I pulled the login logs, the OAuth logs, and eventually a domain-wide export myself and the investigation finally had its identity layer.
When I pulled the Workspace login logs myself, I thought I had it.
The logs showed heavy access to the relevant accounts from overseas IPs stretching back well before the visible attack; it looked like a textbook pre-breach dwell…an attacker quietly sitting inside the environment for a month before making a move. It was the kind of finding that makes a report feel powerful: the compromise started weeks earlier than anyone realized.
I geolocated the IPs before I wrote a word of it and they resolved to India and the Philippines.
Then the client confirmed what those locations actually were: their own offshore staff. The acquiring agency ran legitimate operations out of exactly those regions which meant that the “month-long attacker dwell” was actually just people doing their jobs.
That near-miss became the discipline that governed everything after it: geography isn’t malice; a foreign IP isn’t (necessarily) an attacker. On an organization with global staff, source location alone proves nothing.
So, I needed proof that didn’t depend on where anyone was sitting.
I found it in the OAuth logs, the record of third-party applications authorized against each account.
On two of the compromised accounts at the exact moments they were used to perform malicious actions, someone had authorized a hidden, innocuously-named application granting full Google Ads API access. On the first account, the app was authorized eight minutes before that account invited the attacker into the manager hierarchy. On the second account (during the re-compromise a month later) the app was authorized in the same minute that account re-invited the attackers.
Here’s why that’s bulletproof in a way an IP address never is: authorizing an application requires being logged in and clicking through a consent screen. It’s an action only the account’s controller can take and doesn’t matter where the request originated or whether the login itself was logged..the authorization itself is the fingerprint and it proves the account was under attacker control at that precise moment, geography entirely removed from the equation.
These backdoor apps weren’t just proof, either: they were the attacker’s persistence mechanism. An API token survives a password reset which means you can reset the password all you like but the token keeps working. That’s why the first cleanup failed and the second wave succeeded.
With that, the findings had an anchor that no staff-location revelation could dissolve and once the client confirmed their staff regions did not include the one country these authorizations came from, that country became a clean, unambiguous attacker marker and the rest of the timeline snapped into place around it.
The identity-layer logs had proven the attacker controlled those accounts but they hadn’t yet told me how the attacker got the first foot in the door. A domain-wide login pull answered that and the answer was the least exotic thing in the entire case.
There was an account belonging to an employee who had been terminated roughly a year earlier and never disabled…a live Google Workspace account with working credentials and ad access for a person who no longer worked there. On the morning the takeover began, that account logged in ( flagged suspicious by Google) from Vietnam, and it was the earliest event of the morning, about an hour ahead of the manager-account seizure. Going back further, it had been logged into from a rotating carousel of countries for months.
A terminated employee’s account is the one case where geography genuinely doesn’t matter: there’s no legitimate access to it from anywhere by anyone. Unlike the offshore-staff logins that fooled me earlier, this account had no innocent explanation to rule out and thus every login was unauthorized by definition.
So the most likely entry point to a six-figure-impression advertising-fraud takeover absorbed into an international criminal ad network wasn’t a zero-day or some kind of exotic malware but rather an offboarding ticket that never got filed. A dormant account nobody closed did more damage than any clever exploit in the case and unlike an exploit, it was a process failure the client could actually fix.
There was one more correction waiting for me, and it mattered because I’d already written the opposite into a draft.
Earlier, I’d assessed that credential stuffing (automated password-guessing) wasn’t supported by the evidence, but then a final export showed the night before the takeover in detail: a wave of automated login attempts from rented datacenter servers hammering several of the organization’s accounts, plus a blocked account-seizure attempt from yet another country. I had to revise my own finding: credential stuffing was part of it.
But the texture of those attempts told the real story: they mostly failed. The hardened, actively-used accounts held the line against the brute-force assault. Unfortunately though the attacker got in anyway through the accounts that weren’t hardened: the dormant terminated account and active accounts whose live sessions had been stolen (which sidesteps passwords and two-factor entirely).
That’s the complete picture, and it’s a more honest one than any single-cause theory: a multi-method attack that succeeded through the weakest paths while failing against the strong ones. Brute force bounced off the good accounts, but the forgotten account and the stolen sessions let them in. Security isn’t an average but rather a minimum and the attacker only needed the lowest point in the fence.
Running quietly underneath the technical work was the hardest part of the engagement and it had nothing to do with logs.
The client’s original theory blamed the previous owner of the acquired agency but the logs cleared him as his account showed no involvement…it was never used for an unauthorized action or accessed from nowhere it shouldn’t have been. The villain in the client’s story was, on the evidence, a victim like the others and that alone was a finding the client hadn’t asked for and might not have wanted.
Worse, as the evidence resolved, it kept pointing the same direction: at my client’s own assets. The most likely foothold was a company account on the client’s own domain. A contributing weakness (a shared two-factor arrangement that routed verification codes into a shared team workspace) was the client’s own internal practice. The agency that hired me to investigate a breach was, increasingly, the organization the breach ran through.
There’s an obvious temptation in that position: soften the language, foreground the external attacker, bury the offboarding failure and the shared-2FA habit in an appendix and keep the person paying the invoice comfortable.
I didn’t though for a simple reason: a report that flinches is worthless to the exact end-client it’s meant to reassure. If I’d shaded the findings to protect my client and theirlater discovered the foothold was a year-old un-disabled account, the report (and my client’s credibility with their enterprise customer) would have been worth less than nothing. The independence of the document was its value, so I stated what I had verified, plainly, and was deliberate and honest about disclosure rather than quietly editing the evidence to fit who signed the contract.
The investigation had its smaller integrity tests, too:
Handing over access safely. Getting me the access to do the work meant thinking carefully about what was actually being shared. Most access is just an invitation, no secret changes hands, but admin-level Workspace access required an in-domain account which is the path we landed on and that meant a real credential handoff for the new account’s initial password. I used a defensible approach for that and held one rule with no exceptions: two-factor codes are never shared, full stop.
A line of inquiry that closed. Part of remediation was the end-client taking back administrative control of their own manager account and removing the agency’s access to it. That was exactly the right move for them but my access derived from the agency’s so the moment theirs was revoked, mine was too. The one question it foreclosed was the exact step by which the attacker first reached that manager account; the data that would have settled it now sat behind a door I could no longer open. I documented it honestly as a scope limitation rather than guess at it. Naming the boundary of what you can’t prove is part of the same discipline as grading what you can.
An impatient client. At one point the owner seemed annoyed that the report wasn’t done… before I’d been granted the Workspace access the analysis required. That’s a classic expectation gap: the client had underestimated the work because they believed it was already done. The lesson is to surface that early and concretely (“here is what I still need, and here is what it’s for”) rather than absorb the pressure and cut corners.
The final product was a 25-page, evidence-graded incident report in DOCX and PDF, with a traceable appendix tying every conclusion back to the source export it came from. Three things made it worth more than the client’s original theory:
Every claim is tiered. Findings are sorted into Confirmed (directly evidenced), Assessed (reasonably inferred, with a stated confidence level), and Unable to confirm (not determinable from the materials). The attack vector is labeled assessed, not proven, because it was. That discipline is what lets a reader trust the claims that are marked confirmed.
It draws the one distinction the client most needed. This was an account takeover, not a breach of Google’s platform. Every malicious action used ordinary, authorized account operations: logins, invitations, links, campaign creation. Nothing touched Google’s infrastructure so for an end-client deciding whether to panic about a vendor’s platform, that line is the whole ballgame and the report makes it explicitly and defensibly.
It turns into action. The recommendations follow straight from the findings: immediate, audited offboarding and deprovisioning; phishing-resistant MFA to replace the shared-code habit; a full audit of authorized OAuth applications; Google Workspace admin alerts routed to people who would actually see them; and a scope review of the other accounts under the same manager hierarchy, given the evidence of a broader fraud network.
The final report replaced a comfortable theory with findings tied back to source evidence, confidence levels, and explicit boundaries.
A vague, partly-wrong client theory was replaced with a concrete, defensible root-cause analysis and clear confirmed / assessed / unable-to-confirm boundaries.
The original "blame the previous owner" theory was disproven by the logs and the named suspect was cleared.
Account takeover was cleanly separated from a platform breach, which was the distinction the end-client most needed.
The likely initial foothold was identified as a terminated employee's account that was never disabled, reframing root cause from exotic malware to a fixable process failure.
70+ source IPs were geolocated and classified against confirmed staff regions to separate attacker activity from legitimate offshore work.
Attacker account control was proven through OAuth backdoor authorizations timed to malicious actions, independent of IP geography.
Stolen-session or cookie theft was distinguished from ordinary credential theft, explaining why two-factor authentication did not stop the takeover and why the first cleanup failed.
A coherent multi-method attack timeline was assembled with a fully traceable evidence appendix.
The investigation the client assumed they were only paying to have written up was actually performed.
Collecting reports isn’r investigating. The client had scans, an exposure report, and a theory, and believed the analysis was done, but really it wasn’t started. When something bad happens, the scans tell you where to look; only a real postmortem (primary evidence, a reconstructed timeline, fact separated from assumption) tells you what actually happened and how to stop it recurring.
Geography isn’t malice. On any organization with global operations, a foreign IP proves nothing. The real proof came from an action only an account’s controller can take (authorizing an app) not from where a packet originated.
Discipline is a feature, not a delay. Tiering every claim and refusing to overstate felt slower in the moment but it repeatedly saved the report. Intellectual honesty protected both me and the client. A confident wrong report is a liability with a logo on it.
The boring failure does the most damage. No zero-day in this case did a fraction of the harm caused by an offboarding ticket nobody filed. The most likely entry point was a terminated employee’s account left live for a year. The unglamorous controls (deprovisioning, app audits, killing shared credentials) are the ones that actually move risk.
Independence is the product. When the evidence turned toward the client’s own assets, the honest report was the only valuable one. A document written to keep the buyer comfortable can’t do the job a forensic report exists to do.
And the thing the client originally hired me for (to write up an investigation) turned out to require being the investigation.
The work combined platform-native logs, identity-layer analysis, external exposure checks, and evidence-tiered reporting.
Google Ads change-history exports; Google Workspace login logs, OAuth logs, and domain-wide audit logs; exposure and dark-web reports; SPF, DKIM, and DMARC posture checks.
Change-history reconstruction, OAuth-authorization timing analysis, IP geolocation, and staff-region classification across 70+ source addresses.
Geography-independent proof of account control, login-type analysis to distinguish stolen-session replay from fresh-credential logins, and confidence grading for each major conclusion.
Evidence-tiered findings marked Confirmed / Assessed / Unable to confirm, a source-traceable appendix, and final deliverables in DOCX and PDF.
This case study describes real work performed by Stonegate Web Security. Client details, names, domains, account identifiers, dates, and other identifying specifics have been anonymized or altered.