Here’s a quick experiment. Take any WordPress site, add /?author=1 to the end of the domain, and hit enter. On most installs, WordPress redirects you to /author/some-name/, and that name in the URL is very often the exact username someone types into your login screen. You just gave away half of what an attacker needs, and you didn’t lift a finger to do it.
Author archives are one of those WordPress features that feel harmless because you rarely look at them. They’re the pages that list every post a particular writer has published, and WordPress builds one automatically for anyone who’s ever hit publish. For a busy multi-author magazine that’s genuinely useful. For a one-person business blog it’s usually a security leak and a pile of thin, duplicate pages rolled into a single URL you never asked for.
This guide walks through what author archives actually are, the two real problems they cause, and exactly how to lock them down — whether you want to keep them, hide them from search engines, or turn them off entirely.
What a WordPress Author Archive Actually Is
Every time a user publishes a post, WordPress starts generating a dedicated archive for them at /author/{nicename}/. It’s a chronological list of everything that person wrote, and it’s rendered by your theme’s author.php template (WordPress will use a more specific author-{nicename}.php or author-{id}.php first if one exists, then falls back to archive.php and finally index.php). You never create these pages in the admin. They simply exist the moment there’s an author with published content.
The {nicename} part is the piece that trips people up. WordPress stores several separate name fields for each user, and it’s worth knowing which is which because the fix at the end depends on it:
user_login— the name you type to log in. Set once at account creation and not editable from the normal profile screen.user_nicename— a URL-safe slug that WordPress puts in the author archive URL. By default it’s generated from your login, which is exactly why the URL leaks the login.- display_name — the friendly name shown on the front end (bylines, comments). This one you can change freely, and changing it does not change the URL slug.
So the mental model most people carry — “the byline is my display name, so that’s what’s public” — is only half right. The byline is your display name, but the archive URL is built from the nicename, which was born from your login. Two different strings, two different exposure levels.
A login is half of a login. Once an attacker knows a valid username, a brute-force or credential-stuffing script only has to guess the password — and it can hammer wp-login.php until it does. Author archives hand over that first half for free, which is why username enumeration shows up in nearly every WordPress security scan we run.
Problem One: Your Username Is Leaking
The classic leak is the one from the top of this article. Requesting /?author=1 asks WordPress for the archive of user ID 1, and on a site with pretty permalinks enabled WordPress helpfully 301-redirects the request to that user’s pretty archive URL — which contains their nicename, which is usually their login. Increment the number (?author=2, ?author=3) and you can walk the whole user table. Attackers automate this in seconds; it’s one of the first things a bot tries.
The REST API does the same thing from a different door
Closing the ?author= hole isn’t the whole job. Since WordPress 4.7, the REST API exposes a public users endpoint at /wp-json/wp/v2/users/ that returns every user who has published a post, complete with their slug. It’s public by design so themes and apps can display author information, but for an attacker it’s the same enumeration attack with a cleaner JSON response. Any real fix has to consider both routes, not just the query string.
Why “just don’t use admin as a username” isn’t enough
People hear “username enumeration” and assume the fix is picking a login that isn’t admin. That helps, but it doesn’t solve the problem — it just means the attacker learns jsmith instead of admin. A non-obvious username is still a known username the second it’s in a URL, and the password is now the only thing standing between a bot and your dashboard. The goal is to stop publishing the name at all, not to publish a cleverer one.
Try each of these on your own domain and see what comes back:
- Visit
https://yoursite.com/?author=1— does the address bar change to/author/yourlogin/? - Visit
https://yoursite.com/wp-json/wp/v2/users/— do you see a JSON list withslugvalues? - Visit
https://yoursite.com/author/yourlogin/— is there a full, indexable page there?
Problem Two: Thin, Duplicate Pages Google Doesn’t Need
The SEO side is quieter but just as real. On a single-author site, the author archive is a near-perfect duplicate of your blog index — same posts, same order, same excerpts, just under a different URL. You now have two pages competing to rank for essentially the same content, and neither one is adding information the other doesn’t already have.
It gets worse on a site with a handful of occasional contributors. A guest who wrote two posts three years ago still has a live archive page with two thin entries on it. Multiply that across every person who ever touched the site — including staff accounts that never really published for readers — and you’ve handed search engines a set of low-value pages to crawl. That’s crawl budget spent on URLs you’d never send a visitor to on purpose.
To be clear about the stakes: this is not a “duplicate content penalty.” Google doesn’t hand out a penalty for ordinary internal duplication; it just picks one version, consolidates what signals it can, and moves on. The cost is subtler — split signals between two near-identical URLs, and crawl attention aimed at pages that do nothing for you. On a small site that’s minor. On a large one it adds up, and it’s trivially avoidable.
One more wrinkle worth knowing: since version 5.5, WordPress core ships an automatic XML sitemap, and it includes an author (users) sub-sitemap by default. So unless something intervenes, your author archives aren’t just crawlable — you’re actively pointing Google at them.
How to Fix It: Pick Your Level
There’s no single right answer here, because it depends on whether author pages do anything useful for your readers. A magazine with named columnists wants them. A solo consultant almost certainly doesn’t. Work down this list and stop at the level that matches your site.
Level 1: Keep the archives, but noindex them
If you want author pages to exist for logged-in navigation or for the occasional reader who clicks a byline, but you don’t want them competing in search, tell Google not to index them. Every major SEO plugin makes this a one-click setting. In Yoast SEO it lives under Search Appearance → Archives, where you can set author archives to “not shown in search results,” and on a single-author site Yoast can disable the author archive entirely and redirect it to the homepage. Rank Math offers the same control under its Titles & Meta → Author settings. This adds a noindex directive to those pages so they stay reachable but drop out of the index.
Level 2: Stop the username leak at the source
Noindexing handles the SEO half but does nothing about enumeration — a bot doesn’t care whether a page is in Google’s index. To close the ?author= redirect, you can add a small snippet that blocks the query on the front end. Drop this in a site-specific plugin or your child theme’s functions.php:
add_action( 'template_redirect', function () {
if ( ! is_admin() && isset( $_GET['author'] ) ) {
wp_safe_redirect( home_url(), 301 );
exit;
}
} );
That intercepts any ?author=N request and sends it home before WordPress can reveal the nicename. It’s a targeted fix, and because it hooks template_redirect it only runs on the front end, leaving the admin untouched.
Restrict the REST API users endpoint too
The query-string block above doesn’t touch the REST route, so handle that separately. Rather than disabling the whole REST API — which modern WordPress and the block editor rely on — filter the users endpoint so it only returns data to requests that are actually allowed to see it:
add_filter( 'rest_endpoints', function ( $endpoints ) {
if ( isset( $endpoints['/wp/v2/users'] ) ) {
unset( $endpoints['/wp/v2/users'] );
}
if ( isset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] ) ) {
unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
}
return $endpoints;
} );
Most established security plugins — Wordfence, Solid Security, and others — bundle a “disable username enumeration” toggle that covers both the query string and the REST endpoint, so if you already run one, check its settings before hand-coding anything. There’s no prize for maintaining a snippet a plugin already maintains for you.
Level 3: Turn author archives off completely
On a genuine single-author site, the cleanest option is to not have author archives at all. Redirect every /author/* request to your homepage or your main blog page, so there’s no thin page to index and no nicename to read. A short redirect on template_redirect handles it:
add_action( 'template_redirect', function () {
if ( is_author() ) {
wp_safe_redirect( home_url(), 301 );
exit;
}
} );
With that in place, the archive URL still resolves, but it bounces straight to a real page instead of serving duplicate content. Combined with the ?author= and REST fixes above, the username stops being a public fact and the thin pages stop existing.
The last compromised site we cleaned up had been brute-forced through wp-login.php after the attacker enumerated the admin login straight off the author archive, then dropped a webshell that was quietly serving spam links. None of the individual doors were exotic. The username was public, the login page had no rate limiting, and the password wasn’t strong enough to survive a sustained guess. Closing enumeration wouldn’t have fixed everything, but it would have made the whole attack a lot more expensive to even start.
Don’t Skip the Display Name Fix
Even after you’ve blocked the URLs, there’s a loose end. If you ever leave author archives on — say for a multi-author site — make sure each user’s display name is set to something other than their login. Under Users → Profile, WordPress lets you choose how your name appears publicly from a dropdown, and you should never leave that set to the raw login value. Set a real display name, and the byline shows that instead of handing the login to anyone reading the page.
This matters most for the accounts that already exist, because WordPress fills the “Display name publicly as” dropdown from your login when the account is created. Older sites are full of admin accounts still displaying their login name in every byline and comment. It’s a two-minute fix per user and it closes a leak that no amount of URL redirecting will catch, because the name is right there in the visible text of the page.
A Sensible Default for Most Small Sites
If you don’t want to think about this per-page, here’s a configuration that works for the overwhelming majority of small business and solo sites. Set author archives to noindex (or disable them) in your SEO plugin. Turn on your security plugin’s username-enumeration protection, or add the two snippets above if you don’t run one. And give every real user a display name that isn’t their login. That combination closes the enumeration door, stops the thin pages, and keeps the byline honest — without breaking anything a normal visitor relies on.
Author archives are a good illustration of a wider WordPress truth: the defaults are tuned for the biggest, most general case, not for your specific site. A feature built for a newsroom of fifty writers is switched on for a blog of one, and it quietly does the wrong thing until someone notices. The whole job of hardening a WordPress install is finding those defaults and deciding, deliberately, whether they still make sense for you.
Frequently Asked Questions
Not sure what your own site is exposing? Run the three-line check above, and if the URLs come back live, you’ve got a five-minute fix on your hands.
Built by amplifi.studio — see also our WordPress security hardening checklist.