Sign1 Malware: Injected Scripts That Hide in Plain Sight
By Glenn Lyvers · Updated · 4 min read
You have run a file scanner over the whole install and it came back clean. Core files match, no stray PHP in the uploads folder, nothing odd in the theme. And visitors are still getting thrown onto scam pages. When the files are genuinely clean and the redirects are genuinely happening, the code is almost always somewhere a file scanner never looks — and Sign1 is the campaign that made that lesson famous.
What makes Sign1 different
Sign1 is a JavaScript injection campaign with two tricks that defeat ordinary cleanup. The first is where it lives: rather than writing PHP files to disk, it stores its payload inside the database, commonly in the settings of a legitimate plugin that is designed to output custom HTML or JavaScript into your pages. A widget meant for analytics snippets is a perfect host, because the plugin is real, the feature is real, and the output is exactly what the plugin is supposed to do.
The second is that the code changes. The payload is encoded rather than written in the clear, and the campaign rotates both the encoding and the destination domains regularly. Signature matching struggles with something that does not keep a stable signature, which is why a scan can come back clean on a site that is actively redirecting people.
Why it seems to come and go
Reports of this family consistently describe time-based behavior: the injected code derives part of its logic from the current time, so the domain it points at changes on a schedule and the redirect only fires within certain windows. Add the usual conditions on top — skip logged-in users, skip repeat visitors, only fire for traffic arriving from a search engine — and you get something genuinely difficult to pin down.
The practical consequence is that you cannot clear a site on the basis of a few manual checks. You loaded the homepage, nothing happened, so it must be fixed. It is not fixed; you were simply outside the window or carrying a cookie that excluded you. Treat the absence of a redirect as weak evidence and go looking for the code itself.
Finding it in the database
Start with the places a plugin would legitimately store injectable markup: wp_options rows belonging to header-and-footer script plugins, custom HTML widgets, theme option blobs, and any plugin whose whole purpose is inserting code into your pages. Read the actual stored values rather than trusting the plugin's admin screen, which may render the setting in a way that hides its length.
Search the database for the fragments obfuscation leaves behind — long base64-looking strings, chains of character codes being reassembled, atob, String.fromCharCode, eval in places that have no business containing it. My guide on obfuscated code and base64 covers how to decode what you find safely so you can confirm what it does before you delete it, and database malware covers the other rows worth checking while you are in there.
Confirming from the visitor side
Prove the injection exists by looking at what you actually serve. Fetch a page without a login cookie and read the rendered source rather than the template. If you see a script block or an external script reference that you cannot trace to something you installed deliberately, that is your injection, and its position in the page usually tells you which plugin or theme hook emitted it.
Vary the conditions while you test: a private window, a different network, arrival via a search result rather than a typed address, and a mobile user agent. The goal is to reproduce the behavior your visitors are reporting at least once, because a reproduction gives you something concrete to test against when you think you have finished.
Cleaning it without breaking the site
Clean the specific stored value rather than deleting whole plugin configurations wholesale, or you will lose legitimate settings along with the payload. Where a plugin exists only to inject code and you do not use it, removing the plugin entirely is cleaner and safer than editing it.
Then treat this as a compromise rather than a stray script, because something had write access to your database to put that there. Audit administrator accounts, reset every password, rotate database credentials and salts, and go looking for the file-based backdoor that probably still exists alongside the database injection. A database-only cleanup on a site that also has a PHP backdoor is a reinfection waiting to happen, which is the subject of my guide on reinfection loops.
Keeping it out
The way in is almost always mundane: an outdated plugin with a known vulnerability, or a stolen administrator password. Update everything, remove plugins you do not actively use — especially ones that can inject arbitrary code into your pages, since they make this attack trivially easy — and put two-factor authentication on every administrator account.
It is also worth checking your site the way a stranger does, on a schedule, rather than only when someone complains. Most owners find this class of infection weeks late purely because they only ever view their own site while logged in. If you would rather have someone confirm the site is genuinely clean and keep an eye on it, that is what my cleanup service and monitoring are for.
Common questions
My file scanner says the site is clean. Can it still be infected?
Yes, and this is the exact scenario where that happens. A file scanner reads files. When the payload is stored as a value in a database row belonging to a legitimate plugin, there is no infected file to find. A clean file scan tells you your files are clean and nothing more.
Which plugins get abused for this?
Any plugin whose legitimate purpose is inserting custom HTML or JavaScript into your pages — header and footer script managers, custom HTML widgets, and theme option panels with a scripts field. The plugins themselves are not malicious. They are convenient hosts, because the output they produce looks exactly like the output they are supposed to produce.
Why does the malicious domain keep changing?
Because the payload generates part of the destination from the current date or time, so it rotates on a schedule without anyone touching your site. It keeps the campaign ahead of domain blocklists, and it means a blocklist entry you find today may not match what your site pointed at last week.
Can I just remove the plugin holding the injected code?
If you do not genuinely use the plugin, yes — that is the cleanest fix. If you do use it, remove the specific malicious setting rather than the whole plugin, or you will lose legitimate configuration. Either way it is only half the job, since whatever wrote to your database is still an open question until you find the entry point.
How do I know when it is actually gone?
Test the way a visitor arrives, not the way you do: no login cookie, private window, different network, arriving from a search result, on both desktop and mobile. Then keep watching for a week or two, because a time-conditioned payload can stay quiet through a single round of checks. One clean look is not proof.
More than malware
Most people meet me in an emergency. It isn’t all I do.
I’ve been building and repairing systems since 1995. Whatever brought you here, there’s a good chance I can help with the rest of it too — and you’ll be dealing with the same person either way.
Hacked, but not WordPress?
Joomla, Drupal, Magento, Shopify, PrestaShop, Laravel, Node, IIS and plain HTML — cleaned the same way, priced the same way.
Take a look →Custom builds & AI systems
Plugins, custom applications, website chatbots and automation — built to do exactly what you need, maintained by the person who wrote them.
Take a look →Servers, speed, SEO & accessibility
Migrations, faster load times, technical SEO and accessibility fixes. Measured improvements, with the numbers to show you.
Take a look →Better web hosting
Fast, secure hosting with SSL and backups included at no extra charge. Clear pricing, no long-term contracts, no surprises.
Take a look →Classes & free tools
Rather learn to handle it yourself? I teach this, and I give away the tools I built for my own cleanups.
Take a look →Something else broken?
Half my work is untangling what someone else started, gave up on, or broke. Describe it in plain words and I’ll tell you honestly.
Take a look →Tell me what’s wrong. I’ll tell you what it takes.
No queue, no call centre, no sales pitch — one person who answers, quotes honestly, and does the work.