I Reverse Engineered a Vibe-Coded Klook Phishing Kit
A suspicious Disneyland booking led me to a fake refund flow, an exposed capture log, and a half-built bank approval system.
A post appeared on Threads asking whether someone had bought seven Hong Kong Disneyland tickets and entered the wrong email address.
The screenshot looked obviously fake. It also showed the domain:
klookagh.com
That domain was obviously wrong, so I opened it.
It was a Klook phishing site targeting Hong Kong users.
The seven-ticket booking was the lure. The site offered a refund, collected card details, and finished by asking the victim to approve a “refund” in their banking app.
It also had directory listing enabled.
The server exposed the whole kit.
Flow
The site lived at klookagh.com, a domain registered one day before I captured it.
The flow was:
reCAPTCHA
→ fake Disneyland booking
→ cancel and refund
→ card details
→ approve transaction in banking app
The first page used a real Google reCAPTCHA. Once completed, it submitted a hidden field:
<input type="hidden" name="validated" value="1">
I think the reCAPTCHA was there to keep unwanted indexers and automated scanners away from the phishing flow. It also made the page look slightly more legitimate to victims.
Then it showed a confirmed Hong Kong Disneyland booking.

The booking was hard-coded:
Reference: #HKDL-2026-0821
Date: 21 August 2026
Tickets: 3 adult, 2 child, 2 senior
Total: HK$ 2,836.84
The popup says the invoice will go to the email linked to the victim’s bank account. That line quietly introduces the bank into the story. It becomes important two screens later.
The page also displays qr.png under the heading “Payment Confirmation.”
Scan it and you land on the Wikipedia homepage.
It confirms nothing. It is a random QR code added to make the booking look more technical.
Pressing “Cancel and Refund” creates a hidden form and posts the booking to details.php:
action=cancel_refund
reference=#HKDL-2026-0821
total=2836.84
email=
The site plays a two-second loading animation, then opens the card form.
Card Form
The refund requires:
- Card number
- Cardholder name
- Expiry date
- CCV

The JavaScript accepts a 16-digit Visa or Mastercard number and a three- or four-digit CCV. When the form submits, the button says:
Sending card details...
Very accurate copy.
The form posts to the same details.php receiver with:
action=card_refund
After 30 seconds, it moves to app.php.
Bank Approval
The final page tells the victim to open their mobile banking app, find the refund transaction, and tap Approve.

This is the actual trick.
The attacker initiates a card transaction. The website calls it a refund. The victim sees a real banking notification and approves the charge under that false description.
The page polls an approval endpoint every three seconds:
fetch("check_approval.php")
.then(function (response) {
return response.json()
})
.then(function (data) {
if (data.approved) {
showSuccess()
}
})
It waits for up to 180 seconds. An approved response triggers a fake success popup and redirects to index.php.
Both check_approval.php and index.php returned 404 during capture.
The frontend contains a complete real-time approval experience. The controller behind it was missing.
Vibe Coded
“Vibe coding” originally described telling an AI what you want, running the result, and focusing on whether it appears to work. Collins defines it as using natural-language prompts to assist with writing code.
The files leave the exact tool unknown. The visual design is the strongest clue.
There is already a well-documented visual vocabulary for this. Impeccable’s AI-slop catalog calls out hairline borders paired with diffuse shadows, coloured side borders on rounded cards, and decorative effects with no real purpose. Another UI checklist simply calls it “a card around everything.”
This site hits those patterns almost perfectly.
The whole interface sits on #f4f4f4. Almost every group of information gets wrapped in a white rounded rectangle with a #e6e6e6 border and a soft shadow. The booking is a card. The ticket summary is another card inside it. The refund amount gets its own pale-green card with a thick green border down the left. The approval instructions become another bordered card inside the main verification card.
This is the exact card-on-card-on-card hierarchy that AI frontends keep producing. Everything receives the same radius, border, padding, and shadow, so nothing has a clear level of importance.
The colours also look wrong. The kit defines its main orange as #ff5722 and its stronger orange as #ff4713. Both look redder than the orange in the Klook logo sitting directly above them. It then adds mint green, pale blue, amber, and red status colours with no connection to the branding. It looks like a generic dashboard palette with a Klook logo pasted on top.
Then there is the invoice-email modal.
It covers the booking as soon as the page loads. The same claim about the bank-linked email appears twice. An envelope emoji sits alone at the top. The enormous orange “I understand” button becomes the strongest element on the entire screen.
It feels like a first-pass response to “add a professional confirmation modal.”
The code has the same prompt-by-prompt structure:
Make a Klook booking page.
Add Chinese and English.
Add a refund loading screen.
Make a card form.
Add a bank approval step.
Each file contains its own large block of HTML, CSS, translations, UI states, and JavaScript. One language switcher uses a langData object. Another manually replaces every string inside an if (lang === "en") branch. The booking data moves through hard-coded JavaScript, hidden form inputs, and query parameters.
The likely workflow is simple: describe one screen, accept the generated result, then prompt the next screen. That explains the repeated code, inconsistent implementation, generic visual defaults, and finished frontend states connected to missing backend endpoints.
Hosting
The server itself looks like generic shared hosting.
A Censys snapshot from July 25 shows 24 services on 136.0.111.105, including:
21 Pure-FTPd
25 Exim
53 PowerDNS
80 HTTP
110 Dovecot POP3
143 Dovecot IMAP
3306 MySQL
2083 cPanel
The same IP also exposes the usual cPanel WebDisk, Webmail, SMTP, and IMAP ports. Visiting the IP over HTTP produces cPanel’s “Default Web Site Page.” Port 2083 serves a normal cPanel login.
The certificates use hostnames such as d747.dimedns.com and dev1.dimedns.com. Censys also associates the IP with many unrelated forward-DNS names. PowerDNS even reports that it was built on:
bh-centos-8.dev.cpanel.net
This is a standard multi-tenant cPanel box in Dallas, allocated to HostBudget LLC and announced through Psychz Networks.
The likely deployment story is very simple: the operator bought a cheap shared-hosting account, uploaded a folder of PHP files, and pointed klookagh.com at it.
Their Security
The phishing site used reCAPTCHA to inspect visitors. Its own server published an Index of / page.
Inside /hk/klook/:
app.php
cancel.php
cancellations.log
details.php
hongkongticket.png
loading1.php
logo.png
master.png
qr.png
st1.php
visa.webp
That list maps the entire operation:
st1.phpis the bookingcancel.phpcollects the carddetails.phpreceives the formsapp.phpruns the approval screencancellations.logappears to record submissions
The server also disclosed:
X-Powered-By: PHP/7.2.34
PHP 7.2 reached end of life years ago.
The worst exposure was cancellations.log. I requested its headers and left the body untouched because it could contain victim data.
The response:
HTTP/2 200
content-type: text/x-log
last-modified: Fri, 24 Jul 2026 20:13:28 GMT
content-length: 35997
The file was public, 35,997 bytes long, and modified less than two minutes before my request.
The domain was registered on July 23, 2026. urlscan captured the open root directory around nine hours later.
They launched the campaign and published its blueprint on the same day.
What Still Worked
The missing approval endpoint only affected the last screen.
Card collection happened earlier through details.php. A victim could hand over the card number, name, expiry, and CCV before reaching the broken controller.
This is the uncomfortable part of vibe-coded phishing. AI makes the visible product cheap: bilingual copy, responsive layouts, fake loading states, branded cards, form validation, and polished transitions.
The result only needs to work long enough.
Anyone who entered card details should contact their card issuer, report the card as compromised, review pending transactions, and request a replacement. Anyone who approved the banking prompt should report the transaction as fraud and preserve the original message, link, and screenshots.
The site looked like a finished product. The open directory showed the prompt history.