I'm not sure I really understand the weight this article gives to "nonces"—from an outside perspective, it seems like writing an titled "Exploiting authorization via cookie on Google.com" when you've found a simple XSS. In each case, the problem isn't the nonce itself, but rather the fact that developers are 1) allowing arbitrary file uploads with insecure sanitization, 2) embedding a secret value in frontend JSON blobs that any user can read, or 3) a completely unrelated SQL injection vulnerability.
For #3 especially, it's pretty confusing to single out nonces as especially vulnerable. Any secret defined in wp_config would have been similarly exposed by this exploitation method. For example, the SECURE_AUTH_KEY or the LOGIN_KEY. If you had found an installation that put those values in the database (probably common for multiuser installs), would you have instead written an article that claimed "Wordpress logged in sessions should never be used for authentication"? Or that wordpress auth sessions are "often misused by developers"? Similarly with #2, you make a haphazard effort to tie the improperly sanitized uploaded files back to nonces by saying "a nonce is required to acces the uploaded file", but that really doesn't have anything to do with the vulnerability itself—many users on wordpress installs are required / expected to upload publicly visible files, or files visible to their own user. Or even files visible to the administrator! The method of authenticating access to the files has nothing to do with the vulnerability itself, it was only a small piece of trivia required to properly exploit it in this specific plugin in some cases.
After some thinking: I think a large part of the blame here also falls on the Wordpress documentation. It says that nonces should "never be used for authentication, authorization or access control", but it doesn't explain why. In actuality, nonces seem like they could be a very useful way to authenticate certain actions when a classic authentication session is not available (for example, when sending a user an email that allows them to take an action that they may view on another device or without an existing session, like a "password reset" form, or when authenticating a webhook callback). The fact that plugin developers aren't given enough info to reason through the security implications themselves makes these kind of mistakes more likely, and it also leads to this "cargo cult" security mindset you see in the article where any use of the nonce value magically makes your plugin less secure, regardless of the context. Instead of reasoning through what actually caused the 3 vulnerabilities found, the author just blames the problem on nonces.
And another thing, if Wordpress developers really only want nonces to be used for CSRF prevention alone, why are they so complicated and so exposed to the developer? A more simpler and less "security by complexity" based approach would be to just e.g. use a cookie with a random value and a hidden field with a random value and expect them to match, like Rails does. If these nonces didn't have all of this "hash the user's ID and session token and the current action and add in a 12 hour lifetime" complexity, then developers would be much less tempted to use them for authentication. Additionally, why is the "verify" function exposed to developers at all, instead of being part of a higher level function like "register ajax route" or "register post route"? These are all weaknesses in architecture that make the misuse of nonce values for things beyond CSRF tokens more likely. It's not enough to just write a few lines of documentation and say "There we go, I've secured everything now!". You need to actually figure out what use-cases people are using these functions for and then figure out more secure-by-default ways to address those use-cases, otherwise you're not going to make any progress.
While I do completely agree with you, you also seem to have a much more advanced knowledge of Wordpress than the average developer. I obviously can only speak from my own experience, but to me it seems that Wordpress' popularity mostly revolves around the discoverability of its API, and most developers only consult the documentation when completely stuck on an issue that trial and error doesn't solve.
My experience with Wordpress is more around general PHP security, and reviewing compromised websites to determine whether a cleanup and patch is possible, rather than dumping it and starting over. I'm not sure if improving the documentation and making the API more secure (while also adding some complexity) would fix the vulnerabilities you suggest, or if it would turn less experienced developers away from using Wordpress in the first place. I'm a big fan of adding logging code to user defined functions, to make it easier to get a higher level view of what code is actually executing in a running website.
If you haven't considered it before, and aren't currently involved in it, reviewing Wordpress codebases for vulnerabilities can be pretty lucrative and challenging in an enjoyable way (assuming those you consult with take your advice). Regardless, you seem to be in the small number of vocal developers that might be able to bring about that type of change, for what it's worth.
I know next to nothing about WordPress and haven't used it since I was very little, these opinions just come from my general knowledge of web development, especially trained by my 5 years of Rails experience. Never underestimate the power of a good framework to illuminate the ways in which bad frameworks fail.
The problem isn’t with Wordpress, it’s with it being so accessible that the lowest bar dev shops spit out code as quick and cheaply as possible. Best way to avoid security issues is to not use third party plugins or themes without auditing them.
Even popular plugins don’t do the bare minimum like escaping output.
This reminds me of an article in which brute forcing the WP admin panel was discussed. The problem was that when supplying inaccurate user credentials you would get an error message telling you which was wrong. Their dev stated this was a design choice, that you needed to balance security and user friendlyness.
Security in WP seems more like an afterthought to me, which is a shame to say the least.
It can indeed be incredibly confusing for users if that is not disclosed, bordering on hostile.
It is a common pattern to reregister i.e. when in a hurry so you end up with multiple ids. If you also have userids in addition to email addresses, it can easily become a hard problem in itself to solve/remember which email/pw corresponds to which userid. Obfuscating user/password error messages can make this much worse.
Techies often forget what a messy world non-engineers live in.
It makes it so much easier for attackers - they then can know that a user has an account there too, and can then use that information to find that user's other known passwords. It's offering up information the attacker might not have.
Most applications end up disclosing that anyways either by a success message in the password reset flow, or a "email already in use" message in the registration flow. Obscuring who has an account is a major commitment for the design of any unauthenticated api, one that's both difficult and often user-hostile. And if you trip up once you have a worst-of-both-worlds where you've both made your website worse for your users and attackers can still easily check if someone is a user.
Wordpress takes almost the opposite approach: They consider the fact that you are an author on a page public information. There is even the /wp-json/wp/v2/users api to enumerate them At least they don't show email addresses, but you can also login with the username. ([1],[2] for examples in the wild).
Of course as a wordpress admin you can decide differently: extensibility is one of the core pillars of wordpress. Security arguably is placed behind extensibility and user-friendliness.
While I agree it's not really security through obscurity because when combined with other strategies (like mitigating timing attacks and rate limiting) it does expose less information to the attacker.
However, I stand that it does depend on the application. For example: Facebook does not use generic error messages. I presume because there are other trivial ways to find out if a user has an account so mitigating enumeration through the login form is not actually adding extra security.
It's not quite so clear cut. Close. Even OWASP acknowledges there are trade offs:
> The problem with returning a generic error message for the user is a User Experience (UX) matter. A legitimate user might feel confused with the generic messages, thus making it hard for them to use the application, and might after several retries, leave the application because of its complexity. The decision to return a generic error message can be determined based on the criticality of the application and its data. [1]
Though it's a pretty low bar. Given the common uses of Wordpress, there is certainly a very strong argument that it warrants the extra security.
I'm not defending its UX, I think it should have more generic errors. Just pointing out that this one particular example is not in and of itself the best banner to hold up when it comes to bad security as it is not a clear cut answer. A person could be very considerate of security and still come to the conclusion that the better UX is worth the risk.
I think this is a valid point. At least for frontend usage I can see how less generic messages might make sense. I would still opt for generic messages, but I’m also a little paranoid ;)
To me it’s needless exposure for admin accounts. I can see the value for frontend, client, accounts. However, only if such a service use usernames and not email addresses for logins. Otherwise it would be a great way for attackers to accumelate email addresses related to certain types of services.
Unless your users reuse passwords on other websites, then it is remarkably easy to enter a website. Increasing password complexity doesn't solve the issue with password reuse, and can often have users writing their passwords down on post-its around their desk/monitors.
Increasing complexity makes it harder to brute force hashed and salted passwords from a database. But yes if it is already leaked then you have a problem.
Though I would say that checking against haveIbeenpwnded or another service is a much better mitigation against that.
And 2fa is even better than both.
The truth of the matter is that the owners of most wordpress sites really do not care if it is hacked. Especially if they have a semi decent backup strategy. It is used in so many low stakes deployments that it is kind of silly to force certain levels of security.
Remember it is always about risk/reward. The most secure computer is the least usable one.
I do agree, but with the popularity of Wordpress, I see more and more larger companies using it as a solution. I think the bigger issue is having the site penetrated, then silently serving up malware to your clients, than defacement or anything that would receive attention. I'm not familiar if there is a plugin or solution for integrating a password checking service with Wordpress. I know that it's not difficult to integrate with other CMS solutions.
While not with Wordpress, I've had this conversation multiple times with both management where I'm employed, as well as with client management. I always give pushback when it comes to logins, forgotten passwords, and registrations. Telling someone that a username/email or password is wrong just halved the work needed to break into a system, if not more (since having a username or email correct, with an incorrect password, could allow further social engineering).
For a forgotten password where an email is entered, I always send back a success message. I understand that humans type their emails incorrectly, but allowing a user to enter an email address and seeing a message stating the email wasn't found has now just become a way for an attacker to discover what emails are registered with a website. From there, social engineering becomes much easier, as well as brute forcing ONLY a password and not an email/password combination.
I understand that the complexity in this is due to human frustration, rather than a technology problem. Probably one of the more complex problems to solve. I wish I could paste over these issues by writing more code.
Yes it is a choice and security is a balance. You could encase the server in lead and drop that to the bottom of the sea, but that would be an extreme on the “security” side. You could do away with user authentication completely, that would be an extreme the other way.
1. By common standards, this is considered bad practice, especially in the context in which WordPress operates. User enumeration is widely considered to be an unacceptable consequence of error messages this specific, in most circumstances.
2. There are only very slightly more cumbersome ways to get the functionality desired by this choice (e.g., ‘forgot password’ email loop that’ll email you if you entered an email address for which no account exists).
Bluntly, WP is from a time where security was considered an afterthought, and done very poorly. Especially in PHP land.
They’re undoubtedly carrying a lot of that legacy code, and more importantly, a lot of that cultural baggage.
That definition was made after the sense being used in this article (and this sense has been widely used in cybersecurity in general). Your linked term comes from an acronym written on prison cell doors (Not On Normal Courtyard Exercise) while the meaning of "used only once / unique" has an etymology dating back to Middle English.
“Slut” originally means an untidy woman but if you call someone that, a knowledge of etymology is not going to help. Language doesn’t work based on precedent.
I'm not talking about precedent -- the comment was that it was a poor choice of term, implying that the term in the article came about later.. when the uniqueness sense of the word has been in use since long before that.
Though the slang word looks like it originated in '71 and the cybersecurity use of it only goes back to '78, so perhaps it was a poor choice indeed. Though, with its similarity to the use by dictionary editors and cartographers, it makes sense why they would pick that term.
I only today became aware of the pedophilia reference for it and will have a difficult time unthinking thoughts of revulsion whenever I encounter the security-related term, but what can you do.
> Your linked term comes from an acronym written on prison cell doors (Not On Normal Courtyard Exercise)
These are _always_ backronyms. _Always_. If anyone ever tells you that [random word that's been around for a while] is an acronym, they are _wrong_. (Possible notable exception for 'fubar'; that one's old enough now and probably really is an acronym).
There is imprecision and conceptual forcing and there are sketchy constructs in this post that are annoying given its subject area. It is also shoehorning in other known vulnerability issues to pad out the article, when it is a pretty concise topic.
I am not sure how widespread this specific nonce problem is.
It definitely is a problem -- I am not disputing that.
(Just as it's a problem that people have tended to assume that is_admin() or admin-ajax implies that by the time your hook runs, there's already a valid administrator session, when there isn't. But this is covered in the documentation.)
But the concept here is actually pretty obscure to WP developers so I would imagine they tend to consult the documentation, where they will encounter this at the end of the process:
Nonces should never be relied on for authentication or authorization, access control. Protect your functions using current_user_can(), always assume Nonces can be compromised.
--
As to the rest of the article, I wish it were written less lazily:
> Unfortunately, as history shows, most WordPress plugins, even popular ones, often contain security vulnerabilities.
Most of them often do?
Not so. Definitely someoften do, and there are repeat offenders, and many have, but by volume most WordPress plugins are small and do pretty simple things.
> So far this year, 280 critical (CVSS score 9.0+) vulnerabilities have been found in WordPress and its plugins.
This is disingenuously phrased, to my mind: "WordPress and its plugins" suggests a single authorship and conflates WP with the plugins.
WordPress itself has had no 9+ vulnerabilities this year (or indeed since 2021).
(Not to mention that the post is talking about 280 9.0+ vulnerabilities in seventy thousand plugins, the long tail of which have maybe dozens of activations at most.)
> There are dozens of SQL queries in every WP plugin.
Overreach again. Sure, many (perhaps the majority) of plugins cause additional SQL queries through the posts and options APIs, but most plugins contain little to no custom SQL.
> 280 9.0+ vulnerabilities in seventy thousand plugins, the long tail of which have maybe dozens of activations at most.
This actually is a great point. A few years ago when working on a code analysis tool, we mirrored every single WP plugin and let it chew on them for a while.
It used a mixture of static and dynamic analysis, and “kinda worked” to some extent.
It found more issues than we could reasonably handle, and a lot of them were in plugins with maybe two installs ever and that hadn’t been activated in years.
We ran out of beans before implementing a proper triage system that would score the findings based on popularity or “last updated” data.
I may revisit this sometime though, as my ideas on static and dynamic analysis have come a long way since then!
For #3 especially, it's pretty confusing to single out nonces as especially vulnerable. Any secret defined in wp_config would have been similarly exposed by this exploitation method. For example, the SECURE_AUTH_KEY or the LOGIN_KEY. If you had found an installation that put those values in the database (probably common for multiuser installs), would you have instead written an article that claimed "Wordpress logged in sessions should never be used for authentication"? Or that wordpress auth sessions are "often misused by developers"? Similarly with #2, you make a haphazard effort to tie the improperly sanitized uploaded files back to nonces by saying "a nonce is required to acces the uploaded file", but that really doesn't have anything to do with the vulnerability itself—many users on wordpress installs are required / expected to upload publicly visible files, or files visible to their own user. Or even files visible to the administrator! The method of authenticating access to the files has nothing to do with the vulnerability itself, it was only a small piece of trivia required to properly exploit it in this specific plugin in some cases.