Features Pricing Docs Download
Support
Log in Sign up

Feature Reference

1. Installation and activation

What it does: Adds the GuardForge menu and starts the free protections.

How to access: Plugins > Add New (search for “GuardForge”, spelled as one word — with a space the plugin comes up far down the list; that installs the wordpress.org package), or upload the zip from the purchase email. The free zip at avakode.com/download/ is the Avakode build. Free core first, then the Pro add-on.

Free/PRO: Free installs alone. The Pro add-on refuses to run without the free core and says so in an admin notice rather than fataling; it does not start beside a free core older than 1.6.0 either (see Add-on floor).

Step-by-step:

  1. Install and activate guardforge. Sensible defaults are on from the first request — nothing to configure to be safer than before.
  2. Open GuardForge > Settings and review the hardening switches.
  3. For Pro: install and activate guardforge-pro (the add-on 1.4.1 or newer and the free plugin 1.6.0 or newer go together), open GuardForge → License and click Connect to Avakode: sign in on avakode.com, approve, and the licence on your Avakode account is activated for this site. That works next to either package; the Forge Suite screen of the Avakode build has the same button. The License screen has no key field.

Common questions:

  • *Will hardening break my site?* Anonymous REST requests are limited to an allow-list (oEmbed, Form Forge and GuardForge’s own routes at first) while Restrict REST API to logged-in users is on, which it is by default. Logged-in users, and so the block editor, are not affected. If a plugin’s public REST route stops working, add its namespace under GuardForge > Settings > API & Protocols.
  • *Does it phone home?* Free, wordpress.org package: the checksum lookup at wordpress.org — daily while the file-integrity monitor is on, and when somebody presses “Run scan now” (“Run first scan” in Settings) even with the monitor off — and nothing else. Free, Avakode build: that, plus six more, each on a switch or a press: the advisory download (api.avakode.com, once a day after you switch it on, and on “Fetch now”), “Explain this event”, the feedback answer (api.avakode.com/feedback, on “Send feedback”), “Run diagnostics” on the Forge Suite screen (api.avakode.com/health), “Connect Avakode account” on the AI credits card in Settings (api.avakode.com/auth/connect/init and /auth/exchange to connect, /ai/usage to read the credits left, /auth/credits-connection/revoke on Disconnect) and “Restore from wordpress.org” (core.svn.wordpress.org) — see the Product Overview. Pro, next to either build: with a licence key, the licence check (/licenses/validate), the licensed feed (/security/vulndb, daily) and the update check (/updates/guardforge, automatic, the answer kept twelve hours); on a press or a screen, Connect (/auth/connect/init, /auth/exchange, /licenses/activate), the credits (/credits/balance, /credits/pricing, /credits/purchase/checkout), the free trial (/public/trial/activate) and the Geo-IP lookup (/security/geoip); usage statistics (/telemetry/batch) only after a yes in the prompt, batched on an hourly schedule; the hourly AI verdict (/ai/process) when enabled; and, straight from the site, Cloudflare with your own token and the alert channels you set up.

2. Brute-force protection and the login log (Free)

What it does: Counts failed logins per IP, locks the address out after the limit, and logs every attempt with the IP address, the username tried, the result and the browser’s user agent.

How to access: GuardForge > Settings (limits), GuardForge > Login log (history), GuardForge > Unblock IP (release an address).

Free/PRO: Free. Defaults: 5 attempts, 30-minute lockout, log kept 30 days.

Notes:

  • Behind Cloudflare or another proxy the real client IP is read from the trusted-proxy chain, so a spoofed X-Forwarded-For cannot get somebody else locked out.
  • A row’s result is one of four values: success, failed, soft_locked (staging: counted, not enforced) or locked. In the Avakode build the “Explain” button is drawn only on the three that went wrong — a successful login has nothing to explain, and paying a credit to be told so was the old behaviour; the wordpress.org package has no such button.
  • Pro adds Cloudflare sync (a locked address is also blocked at the edge) and auto-lockdown (a burst of locked addresses can throw the whole site’s lockdown switch).

3. File integrity against the official checksums (Free)

What it does: Compares every core file, and every plugin hosted on wordpress.org, with the checksums wordpress.org publishes for that exact release — api.wordpress.org/core/checksums/1.0/ for core (MD5) and downloads.wordpress.org/plugin-checksums/<slug>/<version>.json for plugins (MD5 and SHA-256). Each file gets one of five verdicts.

How to access: GuardForge > File integrity. Runs daily by cron once the monitor is switched on in Settings (it is off on a fresh install, because the comparison asks wordpress.org for the hashes), and on demand.

Free/PRO: Free, including the plugin and theme walk. The integrity_scope_extras setting decides the scope; there is no licence check anywhere in it.

The five verdicts:

  • official — the file matches the published hash.
  • modified — it is in the published build and does not match.
  • missing — the build has it and this site does not.
  • unexpected — a file that is in no published build at all. This is the one a snapshot-to-snapshot comparison can never produce: a shell that was already on disk when the baseline was taken looks exactly like an unchanged file. Findings are sorted with unexpected first.
  • unreferenced — nothing publishes hashes for it. Every theme, every premium or custom plugin, and any single-file plugin whose wordpress.org slug cannot be derived from its filename. These keep the scan-to-scan comparison and are never counted as clean.

Notes:

  • A 404 from wordpress.org means “no reference”, never “clean”. Reading it as a pass would put a tick beside exactly the files an attacker is likeliest to be living in.
  • Answers are cached per (slug, version): 30 days for a catalogue that exists, 3 days for one that does not — wordpress.org publishes a plugin’s sums slightly after the release, so on release day “not yet” and “never” are indistinguishable. A transport failure is not cached at all; otherwise one timeout would declare the whole of core unreferenced for a month.
  • One scan makes at most ten requests. What it could not reach is queued for the next run and named on the screen, so a site with sixty plugins is covered over a few days rather than in one burst a cron tick cannot survive.
  • The request carries the version, the locale and the slug — not the site address. Guard Forge deliberately keeps the site URL out of the user agent so that sentence can be written down.
  • The hardening score’s integrity_baseline row stops reading “Done” while unexpected > 0.
  • All of it goes through the shared Forge_Net SSRF gate, and class-staging-outbound-surface-test.php enumerates every way out of the free package so a new one cannot be added silently.

4. Restore a core file from wordpress.org (Free, Avakode build only)

What it does: In the Avakode build, puts a “Restore from wordpress.org” button beside a core file that is modified or missing; pressing it downloads that one file from core.svn.wordpress.org and puts it back. The wordpress.org package has no restore, because that package does not write into wp-admin or wp-includes itself: there the same finding is named with its verdict and a link to Dashboard → Updates, where re-installing WordPress puts core files back.

How to access: GuardForge > File integrity, on the finding itself.

Free/PRO: Free, in the Avakode build only; the wordpress.org package does not have it.

The order of the checks is the whole feature — each step is a refusal, not a repair:

  1. The path must be a key in the checksum list wordpress.org published, so there is nothing for directory traversal to work with.
  2. The target must be writable, checked *before* anything is downloaded.
  3. The download must match the published MD5, checked *before* anything is written.
  4. The file being replaced is copied to wp-content/uploads/guardforge-restore/<date and time>/<path of the file>/ behind a deny rule first. It may be a live web shell: a restore that leaves it at a guessable URL has moved the shell, not removed it — and the copy is the only evidence of what was done to the site.

Notes:

  • The restore is written to the audit log, and the restored file stops being a finding in the saved summary immediately, so the screen does not reload with the same row and the same button.
  • Plugin files get no button. Reinstalling the release from the Plugins screen is the safe path, and the screen says so and links there.

5. The audit log and its hash chain (Free)

What it does: Records plugin and theme activity, post and option changes, user and role changes, each with the user, the IP and the time. Since 1.2.0 every row also carries prev_hash (the previous row’s row_hash, or a genesis constant for the first) and row_hash = sha256(prev_hash + canonical JSON of the row’s own fields).

How to access: GuardForge > Audit log, and the “Verify chain” button on it.

Free/PRO: The log, the chain and the verifier are Free. Only the CSV export is Pro.

Notes:

  • What the chain buys: edit one field on one row and that row no longer hashes to its stored row_hash; delete a row and the next one points at a prev_hash nothing in the table produces. Neither is visible in the table itself, which is the point — an audit log an intruder can tidy up is decoration.
  • Rows written before the chain shipped have empty hashes. verify_chain() reads an empty row_hash as “unhashed” rather than as a break, and treats the next hashed row as a fresh genesis. The screen reports “the chain restarted N times” only when N > 1: one restart is the first row and is normal.
  • Writes are serialised with a real cross-connection MySQL named lock (GET_LOCK / RELEASE_LOCK, 3-second timeout, the name carrying $wpdb->prefix so a multisite install does not serialise unrelated sites). Two concurrent writers cannot read the same tail and fork the chain — a fork is indistinguishable from tampering to the verifier, and reporting an intrusion that did not happen is its own kind of failure.
  • verify_chain() walks at most 50 000 rows in one run and says plainly that it was truncated rather than dying half-way on max_execution_time. There is no resumable cursor: a second press re-checks the same oldest part. audit_log_keep_days prunes the table in normal operation, so this ceiling is a guard rail, not the usual path.
  • The log deliberately skips other plugins’ bookkeeping options (*_last_run, *_last_check, transients, cron, rewrite rules, its own keys). On the test stand a sibling plugin’s timer had taken a large part of the log, and a log nobody can read is not an audit. Settings options are never skipped — those are exactly what an operator wants to see change.

5a. Cases: findings turned into work, and the monthly report (Free)

What it does: Groups raw findings into cases so the owner works one thing at a time. There are three kinds: a file the integrity scan cannot explain, an advisory that matches a plugin or theme version that is installed, and a series of login attempts. Cases are built from the last integrity scan, the advisory feed (in the Avakode build; the add-on’s real-time feed replaces it while it is active) and the login log, refreshed once a day and whenever the Cases screen is opened. The wordpress.org package builds no advisory cases, because it carries no advisory feed to read, with the add-on installed or not. A new observation of the same cause attaches to the open case instead of opening a second one.

How to access: Guard Forge > Cases. The monthly report is on the same screen.

Free/PRO: Free, with no licence check, except two remedies that need Pro: Enable lockdown on a login-series case and Apply fix (patch by update) on an advisory case. Without Pro those two are not offered, and a line on the case says Pro is not installed.

Notes:

  • Decisions on a case. Free: acknowledge, assign to a WordPress user, ask for verification and, for a changed file only, explain why the change was expected; for a series of login attempts, Block this IP now, which marks the case mitigated (it is refused if brute-force protection is off, the IP is whitelisted or the site is in staging mode). With Pro two more remedies appear: Enable lockdown on a login-series case (it also marks the case mitigated) and Apply fix (patch by update) on an advisory case, which installs the fixed version WordPress offers if the rule’s own safety checks allow it and marks the case fix applied. There is no free button that marks a fix applied by hand, and no button that makes a case go away without a reason.
  • Mitigated and fix applied are not fixed. Only the plugin’s own recheck can set Fixed: it re-reads the integrity scan, the advisory feed (in the Avakode build) or the login log and confirms that the condition is gone. When a recheck cannot decide (the scan or feed is stale or failed, or the log window is incomplete), a case nobody has acted on yet (still Open) becomes Unverified, never Fixed; a case that already carries a decision stays as it was, and the failed recheck is written to its history.
  • Monthly report: pick a month on the Cases screen. Four numbers, each a count of rows the plugin wrote: detected (cases first seen in the month), checked (cases whose recheck reached a verdict in the month), fixed (confirmed and closed with a recorded basis) and unknown (rechecks that could not decide). Mitigated is its own line and is never folded into fixed. The same numbers download as a CSV file to hand to a client; the file and the on-screen block read the same rows.
  • It does not investigate or clean a compromised site and it is not a clean bill of health: “fixed” means the recheck found the condition gone.

6. Two-factor authentication (Free; the policy is Pro)

What it does: TOTP (RFC 6238) with any authenticator app, plus single-use recovery codes, for the account of whoever is looking at the screen.

How to access: GuardForge > 2FA — the one GuardForge screen that is not administrators-only. It is registered at read, the capability WordPress itself puts on profile.php, so editors, authors, contributors and shop managers can protect their own logins.

Free/PRO: Enrolment, the login challenge and recovery codes are Free. Only the enforce-for-every-administrator policy is Pro (two_factor_policy); its card on the same screen stays hidden below manage_options.

Notes:

  • The enrolment QR is drawn on your own server. An earlier version fetched the image from a third-party QR service with the TOTP secret in the URL — the whole second factor handed to somebody else on every page view. Guard Forge ships its own encoder; the key and an otpauth:// link are printed beside the code for anyone who would rather type it.
  • Deleting the plugin always removes the enrolment table, licence or no licence: it holds shared secrets and recovery codes, and a database outlives the plugin that wrote it.

7. Hardening score and the public badge (Free)

What it does: Scores the installation out of a hundred from twenty-one checks of the site itself, and lists every one with what it is worth, what that weight defends against, and a link to the screen that changes it.

How to access: GuardForge > Hardening score. Recomputed when settings change, once a day by cron, and on demand.

Free/PRO: Free. With Pro installed and licensed one more row joins the same list at the top weight — installed plugins and themes with a published advisory — and the shares are worked out again around it. Without the add-on that row does not exist and nothing on the screen mentions it.

Notes:

  • Every check reads this installation and the score makes no external request of any kind, which is also why it cannot verify a header by fetching the homepage. That promise is worth more than the extra check, and a unit test holds the score’s source to it.
  • A check that cannot apply — the two .htaccess checks on nginx — leaves the sum rather than scoring zero, and the remaining checks grow to fill the hundred, so a correctly configured nginx site can still reach 100.
  • Four weight buckets only (12 / 8 / 5 / 2). The whole table is published in readme.txt and a test compares it with the code, because a score nobody can audit is a score nobody should believe.
  • The score is recorded once a day and kept for a year.
  • The public badge is off until switched on. It publishes a letter grade and the month it was worked out, computed only from the eleven checks a stranger could already run against the site with curl. The numeric score, two-factor coverage, brute-force thresholds, integrity results, pending updates and vulnerable components are never published. The link carries a 32-hex token, can be reissued or revoked, logs nothing, is refused if the site’s host name no longer matches the one it was issued for, and does not exist as a route at all until it is switched on.

8. Staging / development mode (Free)

What it does: Works out whether Guard Forge is running on a copy of the site, and then stops it acting on the outside world. Lockouts are counted and written to the login log as soft_locked but nobody is shut out; the lockout, new-administrator and file-integrity e-mails stop; and with Pro installed the alerts, the Cloudflare push, auto-lockdown, patch-by-update and the credit-spending AI analysis stop too.

How to access: GuardForge > Settings > Staging / development mode. The panel names the signal that decided it and counts what has been held back.

Free/PRO: Free. The Pro modules from 1.2.0 honour it; the guards live inside the add-on, so an older add-on suppresses nothing — and the banner and the settings panel stay quiet about the channels it does not guard rather than promising them.

Notes:

  • Three signals, first match wins: the GUARDFORGE_STAGING_MODE constant in wp-config.php, WP_ENVIRONMENT_TYPE being local/development/staging, or a match against the operator’s list of staging host names.
  • Nothing that can switch the mode on lives in the database. The host list is matched against the address the site is actually served on, so a staging database copied onto production stops matching the instant the domain changes; a plain “staging mode” checkbox would have the opposite property and is deliberately not shipped.
  • Two ways to force production, for a real site mistaken for a copy: the constant set to false, and an “always treat this site as production” setting. Either can only make Guard Forge more protective.
  • In the Avakode build the free advisory feed is deliberately not suppressed on a copy: it is a public read that carries nothing about the site and changes nothing in the world, and a developer’s copy is exactly where somebody looks before they deploy.

9. Vulnerability feed — free, seven days behind (Free, Avakode build only)

What it does: In the Avakode build, once you switch it on, downloads the published advisories for WordPress, plugins and themes once a day from api.avakode.com/security/vulndb-public and matches them, on your own server, against what is actually installed and at which version.

How to access: GuardForge > Vulnerabilities. The screen states, in words, which feed it is reading. The switch exists in the Avakode build only: GuardForge > Settings > Vulnerability database, “Download the public vulnerability feed”, off until you tick it. In the Avakode build, one download on demand is the “Fetch now” button on GuardForge > Vulnerabilities, in the “Refresh feed” card (once the switch is on; before that the card only points to Settings), and, when the daily download is overdue, beside the feed row in the list of checks on the first card of Settings.

Free/PRO: Free, in the Avakode build only. What Pro sells is time, not access: the licensed feed is real time, this one is served with the delay the feed itself declares — seven days at the time of writing. The advisories are public the moment they are issued; withholding them until somebody pays is not a feature boundary. The wordpress.org package has no free feed at all, so there the advisories come from the Pro add-on alone.

Notes:

  • Off until you switch it on. The download is opt-in (vulndb_feed_enabled, default off): activating the plugin never switches it on, and clearing the box in the Avakode build stops the schedule and deletes the advisories already downloaded, because a list that can no longer be refreshed keeps calling a fixed plugin vulnerable.
  • The wordpress.org package has no feed to switch on. Its GuardForge > Vulnerabilities screen says “The advisory database is served by GuardForge Pro, a separate add-on.” and “This build carries no advisory source of its own, so there is nothing to list here.”, and the add-on’s real-time feed (section 10) is the only source there.
  • It is a plain unauthenticated GET. No licence key, no site token, no domain, no list of what is installed — it is the same document for every site on earth, and the matching happens after the download.
  • It is conditional: the ETag and Last-Modified come back as If-None-Match / If-Modified-Since, so an unchanged document costs both sides nothing.
  • It is a snapshot, so ingesting it replaces the free row set rather than merging into it — advisories are withdrawn, merged and disputed, and a mirror that only ever grows keeps warning about them forever.
  • An empty document is refused. On the wire, “this advisory was withdrawn” and “the server had a bad deploy” look identical, and believing the empty one would clear the mirror and print the most reassuring sentence this plugin can print. A document that yields no rows is rejected, the rows already stored stay, the reason is written on the check line, and the ETag is remembered only for a document that was actually accepted.
  • Version matching understands the grammar the mirror really emits: a comma is “or” (several windows for one slug), * is “all versions”, and a hyphen inside a version number — 9.0.0-beta.1 — is not a range.
  • When the Pro add-on is installed and switched on, this client does nothing at all, and on the handover it deletes its own rows, its own options and its ETag: two clients writing one table would let the older document overwrite the newer one.
  • Known gaps in the Avakode build: the free rows carry no summary (the public endpoint’s whitelist does not send one, so the column shows a dash), and the free feed does not yet contribute a row to the hardening score.

10. Vulnerability database — real time (Pro)

What it does: The same advisories, in real time, pulled from POST /security/vulndb with the licence key and the site domain, merged as a watermarked delta rather than a full snapshot.

How to access: GuardForge > Vulnerabilities.

Free/PRO: Pro (vuln_db). It supersedes the Avakode build’s free feed entirely while it is active. In the wordpress.org package it is the only advisory source there is: without the add-on, that package’s Vulnerabilities screen lists nothing.

Notes:

  • Pro rows carry the advisory summary; the record counter on the screen counts only source = 'pro' rows, so a site that used to be on free does not read its stale free rows as coverage of the licensed feed.
  • patched_in is not a field the endpoint sends. Both tiers derive the fixed version from the affected range through the shared GUARDFORGE_Vuln_Range, and only an *exclusive* upper bound (<2.1.4) names one; a sent field still wins over a derived one.

11. Patch by update (Pro)

What it does: Installs the update that closes an advisory against an installed plugin — on cron, one plugin per run — then writes an audit row and e-mails the owner.

How to access: GuardForge > Vulnerabilities, the patch-by-update panel.

Free/PRO: Pro, and off until the operator switches it on, per site.

The rule is a list of reasons not to act:

  • The advisory must name the version that fixes it, WordPress must be offering an update that reaches it, and the offered version must fall outside the advisory’s own affected range. “Merely newer” is not evidence that this vulnerability is closed — a feed that writes 1.0-1.6,<0.9 for one slug derives a fixed version of 0.9, and installing 1.5 on that basis would land back inside the 1.0–1.6 window while the audit row claimed the opposite.
  • A candidate whose range cannot be parsed is refused: “we could not check” must not read as “we checked”. A record whose range is * is therefore never patched.
  • The operator’s allow list, when written, is the whole world; the deny list beats it. The plugin that runs the checkout is a reasonable thing to deny.
  • Never on a staging copy. Never on a plugin directory that is a symbolic link — that is somebody’s working checkout, and an upgrade would replace it with a zip.
  • A failure is remembered for 24 hours, so a plugin whose zip 404s is not re-downloaded on every tick.
  • Cron only. A multi-second download and a filesystem swap inside a page request would sit in front of a visitor, and that request might be the attack.

Notes:

  • Plugins only. Core and themes are out of scope today.
  • The e-mail and the screen name both versions — the one that was inside the range, and the one that is not.
  • The cron event schedules itself from the class constructor rather than from the activation hook: WordPress does not run activation hooks on an update, so a schedule registered there exists on fresh installs and nowhere else. It is scheduled whether or not the rule is switched on, because an operator who enables it six months later must not need a re-activation for it to work.

12. Explain this event (Free, Avakode build only, 1 credit)

What it does: In the Avakode build, puts a button on the rows of the login log that went wrong (failed, soft_locked, locked), on every audit-log row and on every file-integrity finding, asking the Forge AI what that one event means — a severity, a few sentences of plain English, and two to five ordered steps.

How to access: GuardForge > Login log, > Audit log, > File integrity.

Free/PRO: Free, in the Avakode build only: the wordpress.org package has no Explain button, and the Pro add-on does not add one to it. What Pro adds is the automation — the hourly batch that reads everything unasked — not the ability to make the call.

Notes:

  • 1 Forge credit per press. The price is read from GUARDFORGE_Forge_API::CREDIT_COSTS (threat_analyze => 1) and interpolated into the button label and the confirmation, never typed as a literal — a readme quoting a price the Worker does not charge is a mistake this suite has already made once.
  • The answer is stored against the *content* of the event rather than the row that carried it, so asking twice is free and tomorrow’s scan of the same unrepaired file does not charge again. A failed or unpaid call stores nothing.
  • On a site with no licence the first press opens the free trial so there is a balance to spend; that one call sends the site address and the administrator e-mail from Settings → General, once, and never again.
  • Each press sends the log row plus the site address, the WordPress version, the active-plugin count and the theme name, so the answer can be about this site. The prompt is rebuilt from the database, never from the form.
  • With an empty balance a press spends nothing: the notice says “Out of AI credits, so nothing was explained and nothing was charged” and its Top up credits link opens the Forge Suite screen in the admin menu, which is part of the Avakode build.
  • In the Avakode build, once the free trial is used up or has ended, Explain goes on with the credits of a connected Avakode account: press “Connect Avakode account” on the “AI credits” card in GuardForge → Settings, sign in at avakode.com and approve the site; “Disconnect” on the same card removes the connection. The wordpress.org package has no such card.

13. Alerts (Pro)

What it does: Sends security events to Telegram, Slack or a signed webhook — an IP lockout (bruteforce, warn), an integrity change (integrity, critical), a new administrator (account, critical), a malware finding (malware, critical) and a lockdown being thrown (lockdown, critical).

How to access: GuardForge > Alerts. The item comes from the Pro add-on, so a site without it has no Alerts screen.

Free/PRO: Pro (alerts_telegram, alerts_slack, alerts_webhook — one add-on switch turns on all three today).

Notes:

  • A card per channel, no JSON. The screen used to be a textarea of raw JSON with tokens and HMAC secrets printed back in clear text. Now each channel is a card: Telegram (bot token + chat id), Slack (webhook URL), Webhook (URL + HMAC secret + optional header name, default X-GuardForge-Signature), each with an enabled toggle, a minimum severity, a Remove button and “Add channel”.
  • Secrets are encrypted at rest (bot_token, webhook_url — a Slack URL carries its secret in the path — and hmac_secret) and never printed back: the form shows ••••1234. Leaving a secret field empty means “keep and re-encrypt what is there”, so the first save through the new form migrates a legacy clear-text secret without the operator doing anything. Export masks the same way; import goes through the same validation and encryption as the form.
  • Send test really sends, through the same dispatcher, and saves nothing. It reports the HTTP status and the first 200 bytes of the reply.
  • Digest: immediate, hourly or daily. The hourly cron tick both flushes a due digest and releases anything held for quiet hours. Up to 500 events are held pending.
  • Quiet hours are a start and an end in the site’s own timezone, wrapping over midnight, off by default (22:00–07:00 when switched on). They hold ordinary alerts until morning — but lockdown and malware bypass them outright, which is why every signal carries a category separate from its severity.
  • Minimum severity is per channel (info < warn < critical), so the on-call phone can take criticals while the team channel takes everything.
  • Validation: a Telegram chat id is digits (negative allowed, for supergroups) or @channel (5–32 characters); Slack and webhook URLs must be https:// and must pass the shared Forge_Net::is_safe_url() SSRF gate.
  • Alerts have their own admin_post_guardforge_save_alerts handler rather than the generic settings path, because per-channel secrets and validation do not fit a scalar field sanitiser.

14. Lockdown, manual and automatic (Pro)

What it does: One switch that disables user registration, comment submission, XML-RPC and anonymous REST writes while you work out what happened. Thrown by hand it stays on until you turn it off; since 1.2.0 Guard Forge can also throw it itself, and an automatic one lifts itself.

How to access: GuardForge > Lockdown, for the switch and for the Auto-lockdown card with the triggers.

Free/PRO: Pro (lockdown).

Auto-lockdown, and its defaults:

  • Off until switched on (auto_lockdown_enabled, default off).
  • Trigger 1, on by default once auto-lockdown is enabled: twenty distinct IP addresses crossing the brute-force lockout threshold inside a ten-minute window. The threshold is a setting (1–1000, default 20); the window is not, deliberately.
  • Trigger 2, off by default: a single finding from the malware scanner.
  • It lifts itself after auto_lockdown_lift_minutes (default 60, 1–10080) via a one-shot cron event, and a manual lift cancels that event.
  • Both ends are written to the audit log (lockdown_auto_enabled / lockdown_auto_lifted) and the owner gets a plain e-mail. The guardforge/lockdown_toggled action fires, which is what the alert channels listen for.
  • Never on a staging copy, for the same reason a copy does not enforce a lockout.

Notes:

  • Both triggers listen to actions the existing modules already fire (guardforge/ip_locked, guardforge/malware_finding); neither module was edited to add them.
  • The ten-minute window is computed in PHP from the site’s own clock, not from the database server’s NOW(). The login log writes event_time with current_time('mysql') — the *site’s* clock — so on a host whose site runs ahead of its database every row looked like it was from the future and the threshold counted the whole retention window; on a host behind it, the trigger was silently dead.

15. Web application firewall (Pro)

What it does: Inspects each request against ten rules — SQL injection (UNION, tautology, time-based), encoded PHP payloads, command execution, config-file traversal, /etc/passwd reads, script-tag and event-handler XSS, remote file inclusion — and blocks it before WordPress does any further work.

How to access: GuardForge > Audit log, where each block is a waf_block row. The WAF has no screen or setting of its own: it is on while the licence is active.

Free/PRO: Pro (waf).

Notes:

  • Administrators are exempt, and same-site URLs in redirect_to are not treated as remote file inclusion — the two false positives that make firewalls unusable.
  • Every block is logged with the rule that fired, so a false positive is something you can read and fix rather than guess at.

16. Malware scanner (Pro)

What it does: Scans the PHP files under wp-content (.php, .phtml, .phar and .inc) against eight signatures (base64 droppers, packed JavaScript, the legacy /e regex modifier, shell execution through request parameters, dropped phpinfo probes, hex-obfuscated eval, long base64 blobs and known webshell tokens). Quick mode skips files over 1 MB, deep mode files over 8 MB, and the result counts the files it checked, skipped and could not read.

How to access: GuardForge > Malware scanner.

Free/PRO: Pro (malware_scanner). Signatures ship inside the plugin — nothing is fetched for them.

Notes:

  • A finding fires guardforge/malware_finding, which the alert channels and (if enabled) auto-lockdown both listen for.

17. Geo-IP blocking (Pro)

What it does: Blocks or allow-lists whole countries at login, XML-RPC and REST.

How to access: GuardForge > Geo-IP.

Free/PRO: Pro (geo_ip).

Notes:

  • Resolution order: the Cloudflare CF-IPCountry header, a local MaxMind GeoLite2 database, then the Avakode lookup. An unknown country is never auto-blocked — the false-positive cost is a locked-out owner.

18. Cloudflare firewall sync and the edge ranges (Pro)

What it does: Creates an IP access rule in the site’s own Cloudflare zone when Guard Forge locks an address out, and — since 1.2.0 — refreshes Cloudflare’s published list of edge addresses once a day.

How to access: GuardForge > Cloudflare.

Free/PRO: Pro (cloudflare_sync).

Notes:

  • The API token is the site owner’s, scoped to Zone → Firewall Services → Edit, stored encrypted on the site. The call goes straight from the site to Cloudflare; Avakode never holds the token and never relays the request.
  • Repeated locks of the same address inside an hour are skipped, so a sustained attack does not churn the zone’s rule list. Rules Guard Forge creates are tagged in their notes and pruned by a daily cron after the retention window (30 days by default); rules created by hand are never touched.
  • The edge ranges used to be a snapshot compiled into the free core’s class-ip.php. Cloudflare adds ranges, so a site behind a newer edge quietly stopped identifying its visitors — every one of them logged, counted and geo-located as the edge itself, with nothing reporting a problem. The list is now downloaded daily from api.cloudflare.com/client/v4/ips (public, unauthenticated, IPv6 included) through the Forge_Net gate; if the refresh fails the previous list stays in use, and the screen says when it last changed.
  • Like patch-by-update, this daily job schedules itself from its class constructor, not from the activation hook — an update does not run activation, so an activation-only schedule exists on fresh installs and on no site that upgraded.

19. AI threat analytics (Pro, 1 credit a batch)

What it does: Ships a ring buffer of recent security events to the Forge AI hourly and stores a severity, a short narrative of the pattern and two to five ordered steps. It reads the site’s own log — it never invents an event.

How to access: GuardForge > File integrity > AI threat analytics. Off until enabled — each hourly batch spends credits, so the switch has to be thrown.

Free/PRO: Pro (ai_threat).

Notes:

  • The same metered action, prompt and price as the free “Explain this event” button of the Avakode build: 1 credit (threat_analyze), from the same Forge balance every other Forge AI action draws on. What Pro sells is that it runs on its own, hourly, over everything — not the ability to ask.
  • Suppressed entirely while staging mode is on, so a forgotten copy cannot spend the balance.

20. Audit log export (Pro)

What it does: Streams the audit log out as CSV, including both hash columns, so a year of log does not have to fit in memory.

How to access: GuardForge > Audit log > Export.

Free/PRO: Pro (audit_export). Reading the log on screen is free and unlimited; the exporter’s code is not in the free package at all, because a licence check in front of code that shipped anyway is the pattern wp.org rejects.

Forge AI Assistant Online

Hi! I'm the Guard Forge AI assistant. Ask me anything about the plugin — setup, features, troubleshooting, or development.

Just now
Powered by Forge AI · Browse docs