# How to protect your website from spam link injection

> Hackers hide spam links in websites to borrow their search rankings. Learn how link injection works, the warning signs, and how vagejs blocks it on every build.

Most website break-ins aren't about stealing data. They're about borrowing your site's reputation. An attacker slips hidden links into your pages, pointing at casinos, pharmacies or loan sites, and those links quietly pass some of your standing with search engines to theirs. This post explains how that works, how to spot it, and how vagejs makes it hard to pull off.

30 October 2026 · 8 min read · by [Venkatesh A G E](#author)

## What is spam link injection?

Search engines treat a link from one site to another as a kind of recommendation. A link from an established, trusted site counts for more than a link from a brand-new one. That makes trusted sites valuable to spammers, who can't earn those links honestly.

So instead, they take them. Once an attacker can change a website, they typically do some mix of:

-   **Hidden links.** Links added to existing pages but hidden from visitors with styling, tiny text or text the same color as the background. Readers see nothing; crawlers see the links.
-   **Doorway pages.** Whole new pages, often hundreds of them, stuffed with spam keywords and links, sitting at addresses nobody on your team would visit.
-   **Cloaking.** Showing the spam only to search engine crawlers, while normal visitors get the clean page. This is why owners often don't notice for a long time.
-   **Sneaky redirects.** Sending some visitors, often those arriving from search results on a phone, to another site entirely.

The damage builds up slowly. Search engines may lower your rankings or flag the site, browsers may warn people away, and your brand ends up next to words you'd never choose. Cleaning up afterwards takes time, and so does winning back trust.

## How do attackers usually get in?

To inject links, an attacker needs a way to change what your site serves. On a traditional website running server software, the most common doors are:

-   an outdated plugin or theme with a known security hole
-   a weak or reused admin password
-   an admin login page that anyone on the internet can try
-   a database that can be written to through a bug

A static website, the kind vagejs builds, closes those doors. There's no admin panel, no database and no plugin code running on a server. Each page is a finished HTML file. There's simply nothing on the live server to log into or exploit in the usual way.

That doesn't make a static site immune. It moves the target. An attacker would now go after the things that produce your site:

-   **Your content**: a pasted snippet, a guest post or AI-written text with a link slipped in.
-   **Your repository**: a stolen GitHub login, or a malicious change to a dependency.
-   **Your accounts**: your host, your domain registrar, your email.
-   **Your host**: changes made directly to the live files, bypassing your project entirely.

Good protection covers each of these. Here's how vagejs does it, layer by layer.

## Layer 1: a lock on outbound links

The single most effective defense against link injection is simple: decide in advance which websites you link to, and refuse everything else.

Every vagejs site has a `links.lock.json` file listing the outside domains your pages are allowed to link to:

JSON

```
{ "domains": ["github.com", "npmjs.com"] }
```

A link to any domain not on that list fails `vage check`. And because every deploy runs the check first, the link can't reach your live site until someone approves it on purpose:

terminal

```
npx vage links                      # every domain you link to: approved or NEW
npx vage links approve example.com  # approve one (asks first)
npx vage links approve --prune      # forget domains you no longer link to
```

The lock isn't limited to ordinary links. It also covers SVG links, canonical URLs, meta refreshes, iframes and forms, whether they come from your Markdown or from your layouts. New sites require the file, so deleting it is an error too, not a way around it.

In day-to-day use, this is barely noticeable. You approve a domain once, the first time you link to it, and never think about it again. But a spam link added by anyone else, or anything else, stops the build cold.

## Layer 2: no hiding place for links

The point of injected links is that nobody sees them. So vagejs makes hiding them difficult:

-   **Inline styles are removed from page content.** The `style` attribute is the easiest way to hide a link (`display:none`, tiny fonts, off-screen positions), so it doesn't survive into Markdown pages. Styling belongs in your layout and stylesheet instead.
-   **Old tricks are stripped.** Tags like `<font>` and `<marquee>`, and SVG `xlink:href`, are removed from content.
-   **Hidden external links fail the check.** Links to other websites that are hidden with inline styles, marked `aria-hidden`, put inside a zero-size SVG or given no visible text cause an error, in content and layouts alike.
-   **Borderline cases get a warning.** Links inside a `hidden` element or a closed `<details>` get flagged for a look, since real menus use those too.

## Layer 3: content can't carry code

A lot of injection arrives through copy and paste. Someone copies an embed code, a table from another site or a chunk of HTML from an email, and it brings something extra along.

vagejs cleans the HTML inside your Markdown before publishing. Scripts, event handlers like `onclick`, `javascript:` links, iframes and forms are all removed. If you genuinely need an embed, like a video player, it goes in a layout: code you write and review, rather than content anyone might paste.

This also matters when an AI assistant writes your pages. The starter's `AGENTS.md` tells assistants never to add links or pages you didn't ask for, even if a document they read tells them to. That's helpful, but you shouldn't rely on instructions alone, and with vagejs you don't have to. The link lock and the cleanup run no matter who wrote the page.

## Layer 4: a warning for spam vocabulary

Injected spam has a recognizable vocabulary: gambling offers, pharmacy names, quick-loan pitches and the like. `vage check` warns when those words turn up in your pages.

It's a warning, not an error, because some honest sites legitimately use those words. A pharmacy's own website, for example. If that's you, turn it off with `security.spamPatterns: false`.

## Layer 5: check the live site, not just your files

Everything so far protects the path from your files to your host. But what if someone changes the live site directly, through a stolen hosting login, without touching your project at all? Your files would look perfect while your visitors saw something else.

That's what `vage verify` is for:

terminal

```
npx vage verify
```

It renders your site locally, fetches every page from the live site, and compares the two. Links, scripts, event handlers, structured data, text, `robots.txt` and the sitemap all get compared. Anything on the live site that isn't in your project shows up.

It also fetches each page the way Googlebot would, because cloaked spam is often only shown to search engines. Any script on the live site that isn't in your project is an error, except a few well-known ones hosts add, like Cloudflare's analytics, which get a warning so you still know exactly what visitors receive.

You don't have to remember to run it. New vagejs sites include a daily GitHub Actions check. Set the `VAGE_VERIFY_URL` variable in your repository settings to turn it on, and the check fails, and GitHub emails you, if the live site has something serious that isn't in your project, like an added link or script.

## Layer 6: a careful supply chain

Every website depends on code written by other people. On a static site that code runs on your computer and in your build, not on the live server, but it still deserves care.

New vagejs sites run `npm audit` in their CI checks to catch dependencies with known security problems, and get weekly Dependabot pull requests to keep them up to date. Deploys to Cloudflare use a pinned version of Wrangler, Cloudflare's upload tool. The publish commands refuse to commit secret-looking files, like `.env` files, keys and token-like strings, so a leaked password can't become the way in.

## Layer 7: security headers that refuse foreign scripts

When you host on Cloudflare, vagejs writes security headers for your site, including a Content-Security-Policy. That's an instruction to browsers listing the only places scripts may come from. vagejs works it out from your actual pages, so it allows what your site uses and nothing else.

If someone did manage to inject a script tag pointing to their own server, the browser would refuse to run it. Since vagejs pages ship no JavaScript by default, that policy can be very strict without breaking anything.

## What no tool can do for you

We'd be overselling if we stopped there. A framework can't protect accounts it doesn't control. The most important protection is still yours to switch on:

-   **Turn on two-factor authentication** for GitHub, npm, your host and your domain registrar. A stolen password alone then isn't enough.
-   **Protect your main branch** on GitHub, so changes need a review before they land.
-   **Watch Google Search Console** for security notices and for pages you don't recognize.
-   **Be choosy about who can publish.** Fewer accounts with access means fewer ways in.

And if you find a security problem in vagejs itself, please report it privately through the [security policy on GitHub](https://github.com/agevenkat/vagejs/blob/main/SECURITY.md).

## How do you tell if your site is already affected?

Whatever you build with, these are worth a look now and then:

-   Search Console shows pages or search terms that have nothing to do with your business.
-   Searching `site:yourdomain.com` brings up pages you didn't write.
-   Visitors report being redirected, especially on phones.
-   Your page source contains links you don't recognize, especially ones you can't see on the page.
-   Your host or browser warns that the site may be compromised.

On a vagejs site, most of these get caught before you'd notice them by hand: the check catches injected links before publishing, and verify catches changes made after.

## Protection by default

The best security is the kind you don't have to remember. With vagejs, the link lock, content cleanup, hidden-link checks and spam warnings run on every build automatically, and live-site verification is one setting away. You approve the websites you link to once, and from then on anything unexpected stops at the door.

Start a new site with `npm create vagejs@latest my-site` (you'll need Node.js 22.12 or newer), and read [security and spam protection](https://vagejs.com/docs/security/) for every detail mentioned here. If you're weighing vagejs against a traditional setup, our [comparison pages](https://vagejs.com/compare/) cover the differences fairly.

![](https://vagejs.com/images/venkatesh-age-144.webp)

Written by

Venkatesh A G E

Web developer in Bengaluru, India, and the maker of vagejs. Helps startups turn their websites into a real source of customers, with a focus on clarity, technical SEO and AI search.

[LinkedIn](https://www.linkedin.com/in/ageven/)[About](https://vagejs.com/about/)
