Table of Contents
The message that reached an independent financial-advisory practice affiliated with a national broker-dealer network was almost aggressively boring. Subject: ACH Payment Notification. The body ran two sentences, said the confirmation of a sent ACH payment was attached, and closed with a tidy finance-office signature block. One .htm file rode along.
That attachment did not contain the attack. It contained instructions for assembling the attack, and it assembled them in two stages, inside the browser, after the file was already open. Our Adaptive AI scored the message at 90% confidence and labelled it credential theft, and the attachment came back Malicious from the platform's own detonation. What makes the case worth taking apart is not that it was caught, but how little there was to catch on the way in.
SPF Hard-Failed and the Message Still Reached the Inbox
The sending IP had no PTR record and no relationship to the apex domain in the envelope. Received-SPF came back a flat Fail against an explicit record mismatch. There was no DKIM signature. DMARC evaluated to none with action=none. And yet Microsoft's composite authentication reported compauth=pass reason=701.
That looks contradictory and is not. Reason 701 is an implicit pass, and it fired because the spoofed apex domain publishes no DMARC record at all. With no policy on file there was no enforceable verdict to apply, so a genuine hard-fail never became a block. Nothing here authenticated. It failed against a domain owner who had never asked anyone to act on failures.
It is also not a gateway artifact. The Received chain shows the untrusted external IP handing the message straight into Microsoft's own front door, with no third-party gateway in the path to rewrite headers or re-sign the body. It never authenticated at any hop.
The First Decode Happens Before Anything Renders
Open the attachment in a text editor and there is very little to look at. One script block. No form elements, no input fields, no outbound links. Just a very long base64 string literal and a single call that hands it to the browser's built-in base64 decoder, passing the result to document.write.
That one line is the entire outer file. document.write injects its argument while the page is still parsing, so the decoded content becomes real markup. What the mail system inspected and what the browser ran were two different documents.
The Second Decode Rebuilds Its Own Function Name
Decoding that blob yields a complete second HTML document, and that document brings its own script block. Two things about it are deliberate.
First, the variable names are camouflage. They read as ordinary English words picked at random (daourly, belugas, redialled, navigated, intimates, palazzo) with no relationship to what they hold or do.
Second, and more interesting, the inner stage never spells out the decoder's name. Instead of calling atob directly a second time, it assembles the string one character at a time and dereferences it off the global object, written as self['a'+'t'+'o'+'b'](palazzo). Detection logic keyed on the literal token atob near a long base64 blob gets exactly one hit, in the disposable outer wrapper, and never sees it again in the stage that matters. The inner script also tries to lift a token out of the browser's own location string via a disguised regular expression before falling back to its embedded value, a per-visit path that lets the page behave differently when opened outside a real click.
See Your Risk: Calculate how many threats your SEG is missing
The Real Payload Was Never in the Attachment
Once decoded, the inner document injects two remote script references. One points at a genuine, unmodified Bootstrap 4.1.3 file on a well-known public CDN. The other points at a file with the identical name, bootstrap.min.js, served from a Tencent Cloud object-storage bucket in the Singapore region. The bucket label is a mashed keyboard string joined to a numeric account identifier. Tencent is no more a participant than any other cloud provider when someone rents storage and puts something ugly in it, and the same pattern turns up across every major object-storage service.
The camouflage is the point. A browser fetching two files named bootstrap.min.js looks like a page loading a library with a fallback. Only one of them is a library.
Keeping the second stage remote also solves problems for the operator: the emailed artifact stays small and inert, so there is nothing durable to signature, and the payload can be swapped or deleted the moment analysis starts. A sandbox with no egress just sees a broken page.
The Signature Block Belonged to Someone Else
The finance-office signature at the bottom of the body was not invented. It was lifted verbatim from an unrelated organization: a real staff name, title, direct dial, mailing address, and a mailbox on that organization's own domain. The two links in the body pointed at that same organization's real public website, and both scanned clean, because they were. That organization is neither the target nor the attacker. It is template collateral from an earlier build of the kit, and the personal details in that block have been removed here rather than paraphrased.
The personalization worked the same way. The attachment filename and one variable inside the outer script carried an identical base64 token, a reliable sign of a per-target build. That token does not encode the recipient's real mailbox. It encodes the self-addressed identity the attacker put in the From header, which reused the target's own mailbox username on a completely different apex domain, registered nearly three decades earlier and demonstrably outside the attacker's control, since the attacker's own sending IP fails that domain's published SPF record. The Reply-To sat on a second established apex domain more than a decade old. Neither is attacker infrastructure. Both are borrowed.
What Actually Holds Up Against This
The 2024 Verizon Data Breach Investigations Report puts stolen credentials in 38% of breaches and phishing in 15%, with a median 21 seconds from opening a phishing message to clicking. A file that assembles itself after the click is comfortably inside that window.
Three things move the needle. Detonate attachments in an environment that renders them, because advanced attachment and URL inspection that only reads bytes at rest cannot see a document that does not exist until document.write runs. Treat nested decode chains as a signal in their own right: a decoder that rebuilds its own name at runtime has no legitimate explanation. And watch egress for script fetches from object-storage hostnames masquerading as CDN library filenames, the one moment this attack must reach out and identify itself.
An SPF hard-fail with no DKIM and no DMARC policy should not read as neutral just because composite authentication returned an implicit pass. That is the shape our Adaptive AI weighs against sender history and content behavior rather than a single header verdict, and it is why the credential-harvesting label landed at high confidence despite a clean body and clean-scanning links. Both CISA phishing guidance and the NIST definition of phishing frame phishing as deception plus user action rather than a signature to match, which is the right frame for a payload that arrives later and from somewhere else.
The same message came back against the same mailbox less than a week later. Both were mitigated.
Indicators of Compromise
| Type | Indicator | Context |
|---|---|---|
| URL | hxxps://dvfghtyjui87y6t5r4e3-1451377087[.]cos[.]ap-singapore[.]myqcloud[.]com/bootstrap[.]min[.]js | Attacker-controlled second-stage script on a cloud object-storage bucket, disguised with a common library filename |
| URL | hxxps://stackpath[.]bootstrapcdn[.]com/bootstrap/4[.]1[.]3/js/bootstrap[.]min[.]js | Legitimate public CDN file loaded alongside the malicious one as camouflage, not itself malicious |
| IP | 83[.]229[.]81[.]61 | Unauthenticated sending IP, no PTR record, delivered directly into the tenant's own mail filter |
| Hash (MD5) | 9c395d6dce2a15801cf847e23c4441ab | Malicious .htm smuggling attachment |
| Filename | ACH_Payment_notification_[numeric-id]-[mailbox-username]_[base64-token]_2:41.htm | Per-target build; the base64 segment is withheld, and it is duplicated in a script variable inside the file |
| Technique | document.write(atob(...)) | Outer loader writes a full decoded HTML document into the parsing page |
| Technique | self['a'+'t'+'o'+'b'](...) | Inner stage rebuilds the name of the decoder at runtime to avoid a second literal match |
| Auth | spf=fail; dkim=none; dmarc=none action=none; compauth=pass reason=701 | Implicit composite pass caused by the absence of a DMARC policy, not by a genuine alignment pass |
| Subject | ACH Payment Notification | Low-effort finance pretext; the attachment, not the pretext, carries the attack |
MITRE ATT&CK Mapping
| Technique | ID | How it appeared |
|---|---|---|
| Phishing: Spearphishing Attachment | T1566.001 | Per-target .htm attachment delivered under an ACH payment pretext |
| Obfuscated Files or Information | T1027 | Nested base64 encoding, decoy variable naming, and a runtime-reconstructed function name |
| User Execution: Malicious File | T1204.002 | The chain only executes when the recipient opens the attachment in a browser |
| Web Service | T1102 | Second-stage script retrieved from a commercial cloud object-storage bucket |
One Last Thing
A clean static scan of an HTML attachment describes a file, not an attack. When that file's only job is to decode the next one, the chain is what deserves the alert.
Related attacks
| Attack | What happened |
|---|---|
| The PDF Passed Every Scanner. Then It Opened a Browser Tab. | A 46KB PDF arrived clean on every attachment scanner. |
| The Phishing Email That Read Backwards in Its Own Source | Every visible line of this e-signature lure was stored backwards in the HTML source and un-reversed only by a CSS bidi override at render time. |
| The Tax PDF That Every Scanner Declared Clean (It Wasn't) | A tax-season PDF arrived from Gmail with no JavaScript, no links, no forms, and a clean verdict from every scanner. |
| The Auth0 Developer Tenant That Passed Every Security Check (Because It Was Real) | An attacker weaponized Auth0's free developer tenant to build a phishing chain that passed DKIM, DMARC, and every link scanner. |
| The Spreadsheet With No Macros and One Hidden Link: External Relationships in Office XML | An Excel spreadsheet from a construction company passed every scanner as clean. |
Explore More Articles
Say goodbye to Phishing, BEC, and QR code attacks. Our Adaptive AI automatically learns and evolves to keep your employees safe from email attacks.