Yaamlabs
Vulnerabilities

pfSense pfBlockerNG flaw: one DNS reply to a root shell

CVE-2026-78902 lets a crafted DNS reply plant script in pfBlockerNG reports and turn an admin's visit into root on pfSense. Who is exposed and what to do.

By Yaali. September 29, 2026, 6 min read, Vulnerabilities, Patching.

Cover illustration of a rack-mounted firewall with a stream of small packets flowing along a glowing cable into a floating dashboard panel, with the Yaamlabs logo and the text: One DNS reply can put root on your pfSense, pfBlockerNG 3.2.16_1, the fixed package

NetSPI published research on September 22 showing how a single DNS lookup can end with an attacker holding a root shell on a pfSense firewall. The flaw, CVE-2026-78902, sits in pfBlockerNG, the add-on package that gives pfSense DNS blocklists and IP feeds and one of the most widely installed packages on the platform. A crafted DNS reply plants JavaScript in the package's report pages; when an administrator opens those reports, the script uses the admin's own session to run shell commands on the firewall.

You are exposed if pfBlockerNG's DNSBL (DNS blocklist) feature runs in Unbound Python mode with DNS Reply Logging switched on, and the package is older than 3.2.16_1. The CVE record, published September 25, names pfSense 26.03.1-RELEASE and scores the flaw CVSS 6.1. That score measures the script injection alone; NetSPI's write-up shows it reaching root. Netgate shipped the fix in early July, so the firewalls at risk are the ones whose packages have not been updated since.

Attack chain for CVE-2026-78902: a LAN client resolves an attacker domain, the TXT reply is written unescaped to dns_reply.log, an admin opens the pfBlockerNG Stats report, and the injected script uses diag_command.php to run a root shell

How it works

With DNS Reply Logging enabled, pfBlockerNG records every answer the Unbound resolver returns and shows them under Firewall > pfBlockerNG > Reports, on the DNS Reply tab and a Stats tab that aggregates them. The logging is done in Python by pfb_unbound.py. According to NetSPI, its convert_other() function turns the raw data of less common record types into text and keeps every printable ASCII character, including the HTML metacharacters <, >, ", ' and =. The result goes into /var/log/pfblockerng/dns_reply.log as is.

The attacker only needs to control the authoritative name server for a domain and get something on your network to look it up. A TXT record, which can carry arbitrary text, is enough. Netgate's own bug report (#16932) describes exactly this: reply text from an attacker's server shown to the administrator without encoding. Any client that asks your resolver for that name will do, and a link or an embedded image is enough to make a browser ask.

The stored payload fires when an administrator opens the report. The page pfblockerng_alerts.php printed the logged "resolved address" field into table cells, a title attribute, filter buttons and chart labels without HTML encoding, so the browser executed the attacker's markup as part of the pfSense web interface. NetSPI found the Stats page the most reliable place for it to land. Cross-site scripting (XSS) of this kind means the script runs with the admin's cookies and privileges.

From there, NetSPI's script loads more code from an attacker server, requests /diag_command.php (the built-in Diagnostics > Command Prompt page, which runs shell commands as root), scrapes the CSRF token from the response and posts a command back with it. A CSRF token is the per-session value pfSense uses to confirm a form came from its own page, so a script running inside that page can read and reuse it. In NetSPI's demonstration the command fetched and ran a reverse shell script, and a root shell connected back to the researcher.

What attackers are doing

No exploitation in the wild has been reported. CVE-2026-78902 is not in CISA's Known Exploited Vulnerabilities catalog, and vulnerability trackers list no public exploit tool. NetSPI's post describes the full chain in enough detail to rebuild it, though, and the entry point is a DNS lookup from any internal device, not network access to the firewall.

The disclosure itself was quick. NetSPI reported the flaw on July 1, Netgate confirmed it on July 2 and pushed pfBlockerNG 3.2.16_1 soon after, MITRE assigned the CVE on September 9 and NetSPI published on September 22. Netgate forum users noticed 3.2.16_1 in the package manager by July 8 and asked in vain for a changelog, so the update carried no security notice.

What to do

Priority actions for CVE-2026-78902: update pfBlockerNG to 3.2.16_1 or later, turn off DNS Reply Logging if you cannot update today, check dns_reply.log for HTML characters, and rotate credentials and review the firewall if you find any

1. Update the package

Open System > Package Manager > Installed Packages and check the version of pfBlockerNG or pfBlockerNG-devel. Anything below 3.2.16_1 needs the update. Netgate's July fix added a safe() function that strips commas, control characters and non-ASCII bytes from the query name and reply fields before logging. In late September the pfBlockerNG maintainer merged further hardening (pull request #3320) that escapes < > " ' & and control characters in both dns_reply.log and dnsbl.log, so watch for that in the next release as well.

2. If you cannot update today

Under Firewall > pfBlockerNG > DNSBL, clear the DNS Reply Logging option and save. That stops new replies reaching the log. Until you have checked the existing log (step 3), do not open the DNS Reply or Stats report tabs, because the payload fires on viewing.

3. Check for injected content

From a shell on the firewall (not the web interface), search the logs for markup:

grep -E '[<>"]' /var/log/pfblockerng/dns_reply.log /var/log/pfblockerng/dnsbl.log

Legitimate hostnames and IP addresses never contain those characters, so any hit deserves a look, especially <script, onerror= or a URL to an unfamiliar host. If you find a payload, look through your firewall and proxy logs for connections from the firewall's own address to the internet around that time, and compare recent entries under Diagnostics > Backup & Restore > Config History for users, rules or packages nobody added. Commands run through the Command Prompt page do not change the configuration file, so a clean history does not prove nothing ran.

4. If you find signs of compromise

Treat the firewall as fully compromised. Reinstall it on current pfSense, restore a configuration backup from before the injection date, and read through that backup for unexpected accounts or rules before importing it. Then rotate what the box held: every web interface password, VPN pre-shared keys and certificates, RADIUS and LDAP bind credentials, and any dynamic DNS or API tokens. Log out every active session afterwards, since a stolen session cookie outlives a password change.

The wider lesson

Restricting the webConfigurator to a management network, with the anti-lockout rule replaced by an explicit allow rule under System > Advanced > Admin Access, is good practice, and it stops attacks that need to reach the login page. It would not have stopped this one. The attacker never touched the web interface: the admin's browser, already on the management network, did the work. Any feature that displays data from outside, whether DNS replies, DHCP hostnames or VPN usernames, can carry a payload into the admin interface.

Two habits reduce that risk. Give day-to-day monitoring accounts a pfSense user without the "WebCfg - Diagnostics: Command" privilege, so a script running in their session cannot reach the Command Prompt page. And keep an inventory of package versions alongside the base system, because package fixes like 3.2.16_1 arrive without an advisory.

Our network penetration tests include firewalls and their management interfaces, and our safeguarding and hardening work covers admin roles, logging options and package hygiene on appliances like pfSense. Open the chat and Yaali, our AI agent, will pass your question to an engineer.


Sources: NetSPI research, pfSense bug #16932, pfBlockerNG issue #3319, pfBlockerNG pull request #3320, Netgate forum on 3.2.16_1, TheHackerWire CVE entry, Strix CVE entry, OffSeq Threat Radar, Netgate docs on restricting management access, Netgate docs on configuration backups.

Read next

Back to the blog, or tell us about your system in the chat. Yaali, our AI agent, answers first and brings in an engineer.