- Treat every value from a browser, URL, form or API as untrusted until validated.
- Nonces stop forged requests, but capability checks decide who is allowed.
- Escape late, on output, and prepare every database query that includes variables.
- Owners reduce risk by removing unused plugins, updating quickly and testing code before install.
Why plugins are the weak point
WordPress core is reviewed heavily. Plugins vary from excellent to dangerous, and they run with the same power as the site itself. A flaw in a small contact form plugin can let an attacker create an administrator, read customer data or upload a file that runs code. Security reports on WordPress sites consistently point to plugins and themes, not core, as the common entry route.
That makes two groups responsible. Developers must write code that treats every request as hostile. Site owners must choose, update and remove plugins carefully, because an abandoned plugin keeps its vulnerabilities forever. This guide covers both sides, with the vulnerabilities in the order we meet them during reviews.
If you are building something custom, our WooCommerce plugin overview and costs explains where security work fits in a project, and our plugin development services build these checks in from the first commit.
The common vulnerabilities at a glance
Learn these names, because security advisories and scanner reports use them.
Vulnerability | What goes wrong | Core fix |
|---|---|---|
Cross-site scripting (XSS) | Untrusted text is printed as active HTML or script | Escape output with the correct function for the context |
SQL injection | User input changes the meaning of a database query | Use prepared statements and avoid string-built SQL |
Cross-site request forgery (CSRF) | A forged request makes a logged-in user act unknowingly | Verify nonces on every state-changing action |
Broken access control | A user performs an action beyond their role | Check capabilities and ownership on the server |
Insecure file upload | An attacker uploads executable code | Restrict types, validate content and store safely |
Insecure direct object reference | Changing an ID reveals someone else's record | Confirm the current user may access that object |
Unsafe deserialization | Crafted data triggers code to run | Avoid unserialising untrusted input, prefer JSON |
Fixing the big three in code
These habits prevent most of the vulnerabilities that appear in advisories.
- Sanitise and validate on inputUse WordPress sanitising functions for text, emails and URLs, and validate against allowed values. Reject what does not fit instead of cleaning it up and hoping.
- Escape on outputUse esc_html, esc_attr, esc_url and wp_kses for the context where data appears. Escape as late as possible, at the moment of printing.
- Prepare database queriesUse the database class's prepare method for any query containing variables, or better, use WordPress query helpers that handle this for you.
- Add nonces to forms and actionsCreate a nonce when you render the form or link, and verify it when the request arrives. Do this for AJAX and REST calls that change data.
- Check capabilitiesAsk whether the current user is allowed to do this, using a capability, never by testing whether they are on an admin page.
- Secure REST endpointsGive every route a real permission callback. A callback that always returns true makes the endpoint public.
Nonces are not permissions
A common misunderstanding causes serious bugs. A nonce proves that a request came from a page your site generated for that user. It does not prove the user is allowed to perform the action. An editor with a valid nonce can still call an administrator-only function if the code never checks capabilities.
Always pair the two. Verify the nonce to stop forged requests, then verify the capability to stop privilege abuse. For actions on a specific record, such as editing an order or deleting a booking, also confirm the user owns that record or may manage it. This third check prevents the insecure direct object reference problem, where changing a number in the address bar opens another customer's data.
For payment and order plugins, these checks protect money. Read our notes on custom payment gateway plugins for Pakistani stores for the extra rules on callbacks and signatures.
Which escaping function fits which place
Escaping depends on where the value is printed. Using the wrong one is a frequent cause of leftover XSS.
Where the value appears | Function family | Note |
|---|---|---|
Between HTML tags | esc_html | Plain text only |
Inside an attribute | esc_attr | Quote the attribute in your markup |
In a link or src | esc_url | Also blocks unsafe protocols |
Inside JavaScript data | wp_json_encode or esc_js | Prefer passing data through localised script objects |
Allowed rich HTML | wp_kses with an allowed list | Define tags and attributes explicitly |
In a textarea | esc_textarea | Preserves line breaks safely |
What site owners can do without writing code
Most compromises happen through plugins the owner already has installed.
- Remove what you do not useDeactivated plugins can still be attacked if their files remain. Delete them.
- Update promptlyApply security updates quickly, but test on staging first for plugins that touch checkout or orders.
- Check maintenance signalsLook at the last update date, support activity and whether the author responds to reports.
- Prefer fewer, better pluginsEach plugin widens the attack surface. Replace several small ones with one trusted option where sensible.
- Limit administrator accountsGive staff the lowest role that lets them work, and use two-factor login for administrators.
- Keep backups you have testedA backup you cannot restore is not a backup. Store copies away from the server.
- Monitor and hardenOur WordPress security hardening service covers scanning, firewall rules and file permissions.
Reviewing a third-party plugin before install
You do not need to read every line to learn a lot. Open the plugin folder and search for places where it reads request data, runs database queries and registers AJAX or REST routes. Check whether each one has a nonce, a capability check and sanitising. A plugin that handles uploads, remote requests or eval-like functions deserves closer attention.
Look at the changelog too. Healthy plugins mention security fixes plainly and ship them quickly. Plugins that have gone silent for a long time, or that ignore reports, are poor long-term choices even if they work today. Run a trial on staging with a scanner and a debug log turned on, and watch for notices that hint at sloppy code.
Mistakes developers keep repeating
None of these is exotic. They show up in routine code reviews.
Trusting hidden fields
Hidden inputs, cookies and URL parameters are all editable by the user.
Escaping too early
Cleaning data when it is saved leaves you unsafe if it is later printed in a different context.
Open AJAX handlers
Handlers registered for logged-out users without checks are public endpoints.
Leaking in error messages
Detailed errors and debug output reveal paths and queries to attackers.
Storing secrets in code
API keys committed to a repository get copied and reused. Use settings or environment variables.
Skipping review before release
Most flaws are found by a second person reading the code with a hostile mindset.
Security for Pakistani agencies and store owners
In Pakistan, a lot of sites are built quickly on nulled or pirated premium plugins to save licence fees. This is the most avoidable risk we see. Nulled plugins often include hidden backdoors, and they never receive legitimate updates. The licence fee is cheaper than an incident, both in lost orders and in cleanup.
Hosting choices matter too. Shared servers with outdated PHP, no isolation between accounts and weak file permissions turn one infected site into many. Choose hosting that supports current PHP versions and account isolation, and keep logins and file access limited to people who need them. Freelancers who leave a project should have their access removed the same day.
Stores handling customer addresses, phone numbers and order history carry real responsibility, even where privacy law is still developing. If you accept payments, keep card data entirely with the provider. We help here under plugin customization services, where we review and harden plugins that already run on your store, and our wider WordPress security checklist gives a broader routine.
If you think a plugin has been exploited
Act in this order and keep notes.
- ContainPut the site in maintenance mode or restrict access, and change administrator, hosting and database passwords from a clean device.
- Back up the evidenceTake a copy of files and the database before cleaning, so the cause can be investigated.
- Find the entry pointCheck the plugin list against known advisories, review recently changed files and look for unknown administrator users.
- Clean and restoreReplace core, plugin and theme files with fresh copies, remove unknown files and restore from a clean backup if needed.
- Patch and reviewUpdate or remove the vulnerable plugin, rotate API keys, and review logs for data access.
- Tell people if requiredIf customer data was exposed, inform affected customers and your payment provider as your agreements require.

Junaid's take
In my experience, security problems come less from clever attackers than from small shortcuts: a missing permission check added late, a plugin nobody updated, a cracked theme installed to save a licence fee. Boring discipline beats clever defence.
If I owned a store today, I would keep the plugin count low, buy licences for anything commercial, run updates on staging first and insist that every custom plugin gets a code review for the checks above before it goes live. I would also keep one tested backup off the server.
If you have a custom plugin and you are not sure it has been reviewed, get in touch. We can read the code, report what we find in plain language and fix it. You can also see how we approach Laravel development services where the same principles apply to non-WordPress projects.

