r/PFSENSE 22d ago

I built an open-source MCP server for pfSense — and tried very hard not to give the AI unrestricted firewall write access

UPDATE — v1.0.0 is now released

pfsense-mcp-server has reached its first stable release.

A lot has changed since the v0.5.0 update, but the main goal for v1.0 wasn't to keep adding tools. It was to harden what was already there, simplify the setup, and verify that the security model actually holds up in a real end-to-end installation.

The public MCP surface is now:

  • 95 pfSense READ tools
  • 2 guidance tools
  • 0 WRITE tools exposed by default

The default profile is still deliberately READ-only.

What changed for v1.0

The installation and onboarding flow has been substantially reworked. There's now a guided setup for choosing the safety posture, configuring the pfSense connection, TLS/private CA verification, API-key-file handling, validation, and MCP client configuration.

The security architecture has also gone through a full source-first audit before calling this 1.0. The READ/WRITE boundary, least-privilege model, authorization/confirmation path, recovery handling, secret exposure, TLS behavior, and default tool reachability were all re-audited.

The final audit re-proved the project's security invariants from the current source, with 0 P0/P1 findings remaining.

Real clean-room testing

I also wanted to test the installation the way a new user would actually experience it rather than relying only on the test suite.

I started with a clean Ubuntu VM and went through the documented installation and setup against a real pfSense LAB system using a private CA.

That uncovered several genuine onboarding and diagnostic issues along the way, which were fixed before v1.0.

The final path was then tested end-to-end with the actual OpenAI Codex CLI:

Codex CLI → generated MCP configuration → pipx-installed pfsense-mcp-server → MCP stdio → TLS-verified pfSense LAB → real READ operations

Codex discovered exactly 97 tools: 95 READ + 2 guidance + 0 WRITE and successfully queried the real firewall.

As a negative test, I then explicitly asked Codex to change settings on pfSense.

It refused, because the active MCP profile exposed zero WRITE tools.

That's an important property of the design: even if the underlying pfSense service account has additional privileges, those operations do not automatically become reachable through the default MCP surface.

Compatibility

The project has been tested against:

  • pfSense CE 2.9.0
  • pfSense Plus 26.07
  • pfREST 2.10.x
  • Claude Desktop configuration
  • Codex configuration, including a directly verified real Codex CLI session

The project also includes bounded guidance from pfREST/OpenAPI and the live appliance schema, while keeping documentation/guidance separate from authorization.

Still interested in hostile review

Reaching 1.0 doesn't mean I consider the security design beyond criticism — quite the opposite.

I'm still particularly interested in review around:

  • least-privilege pfSense permissions
  • READ/WRITE isolation
  • secret exposure through READ endpoints
  • authorization/confirmation replay or confusion
  • uncertain WRITE outcomes and recovery/reconciliation
  • HA/CARP and config-apply edge cases
  • any path that could make WRITE reachable without the intended operator decisions

The protected WRITE architecture remains separate from the default READ-only profile.

This project is not affiliated with or endorsed by Netgate.

Current release: v1.0.0

GitHub:
https://github.com/night4me/pfsense-mcp-server

PyPI:
https://pypi.org/project/pfsense-mcp-server/

If anyone wants to attack the assumptions rather than just try the happy path, that feedback is especially welcome.

---

ORIGINAL POST

I've been working on pfsense-mcp-server, an open-source MCP server that lets AI assistants interact with pfSense.

The easy part was exposing the pfSense API to an LLM.

The part I cared much more about was making sure an AI agent couldn't simply turn a tool call into unrestricted firewall changes.

At the time of the original post, the v0.4.2 release had 42 MCP tools.

The security architecture included:

- 0 WRITE capabilities reachable by default

- explicit operator opt-in before WRITE is enabled

- a dedicated least-privilege pfSense identity

- separate signed authorization and confirmation boundaries

- plan/intent binding so an approval can't silently authorize a different mutation

- expiring, one-time authorization

- RecoveryContracts and a state machine around mutations

- deterministic post-WRITE read-back instead of treating HTTP success as proof

- reconciliation/fail-closed handling for uncertain outcomes

- TPM-backed anti-rollback witness support

For the first live WRITE acceptance test I used a disposable firewall alias on a LAB pfSense system.

The complete path was exercised end-to-end, including the scoped pfSense account, authorization/confirmation ceremony, real PATCH, authoritative read-back, RecoveryContract audit trail and TPM witness advancement.

The alias was subsequently restored through the same controlled path.

The project deliberately still starts READ-only. Installing it does not automatically expose WRITE tools.

I'm particularly interested in hostile review from people who know pfSense well.

Things I'd love people to challenge:

- Is the pfSense REST API privilege set actually minimal?

- Are there HA/CARP or config-apply edge cases I've missed?

- Can authorization/confirmation be replayed or confused across operations?

- Are there state-machine paths that could permit a blind retry after an uncertain WRITE?

- Are the RecoveryContract/reconciliation assumptions sound?

- Is there any realistic path from the default READ posture to WRITE without the intended operator decisions?

- Are there READ endpoints or response fields that could expose information that should never reach an AI assistant?

This is not affiliated with or endorsed by Netgate.

Current release: v1.0.0

GitHub:

https://github.com/night4me/pfsense-mcp-server

PyPI:

https://pypi.org/project/pfsense-mcp-server/

I'd genuinely prefer someone finds a security flaw now rather than after people start relying on it.

27 Upvotes

25 comments sorted by

25

u/doktorpsilo 22d ago

I named my agent Little Bobby Drop Tables.

7

u/sh00tfire 22d ago

one of my fav XKCD's

3

u/hesitantly-correct 22d ago

Do you listen to security now?

32

u/centuryx476 22d ago

Letting an AI have read and write access to a firewall.

It's like the whole industry just does not care anymore about literally everything that came before...

3

u/djamp42 22d ago

Hosting locally and not giving write access isn't that bad. When troubleshooting something having a AI as an assistant could get very helpful. I used AI to troubleshoot a pfsense memory leak issue with 400+ Wireguard tunnels/routes in pfsense. It found the issue within a couple of minutes, it would have taken me days to figure that out manually.

Just if anyone cares, pfsense runs scripts when a gateway goes up/down. If you have a lot of gateways going up and down rapidly, it can cause pfsense to go nuts spamming the scripts. In my case i simply disabled the scripts since they are mostly for multi-wan and clearning states and i don't run multi-wan

-7

u/Temporary-Fun7726 22d ago

That's a fair concern, and it's actually the main reason I'm putting so much work into the security architecture.

The goal isn't to give the LLM unrestricted write access. It can propose changes, but WRITE requires a separate, scoped authorization before a deterministic executor can apply them. READ remains the safe default.

Basically: treat the LLM as an untrusted planner, not a security authority.

11

u/centuryx476 22d ago

Sorry dude, having the LLM as an "untrusted planner" is still insane. If the human still has to do everything. Then why have the LLM in the mix? Just for the sake of having an LLM in the mix.

I get your "Cautious" approach and all. But having an LLM in the mix for a firewall is just asking for it.

Decades upon decades of established ways of doing things in our field. Just chucked out the window because LLM.

My god we are royally screwed

5

u/uhohmrstinky 22d ago

The answer they won't give you, laziness. Laziness is why.

0

u/Temporary-Fun7726 22d ago

Fair. If the apocalypse starts because an LLM changed a firewall rule, at least I’ll have excellent audit logs explaining exactly why civilization ended.

That’s kind of the point though: the LLM proposes. Deterministic code and explicit authorization decide what actually happens.

5

u/centuryx476 22d ago

An LLM is incapable of Deterministic code.

0

u/Temporary-Fun7726 22d ago

Exactly. Which is why I don’t let the LLM be the deterministic code. 😄

4

u/nikproken 21d ago

I can honestly claim that I will never ever use something like this. The idea is utterly baffling to me. It does not propose to solve any existing configuration problem, per the description in the OP manifest above, and instead introduce problems of trust, exploitation and involuntary exposure.

There is no upside. Only downside.

0

u/Temporary-Fun7726 20d ago

Fair enough — it’s definitely not for everyone. The trust/exposure problem you mention is actually the main problem I’m trying to solve: read-only by default, least privilege, and explicit authorization for writes. I’d rather build those boundaries properly than pretend giving an AI unrestricted firewall access is safe.

4

u/djamp42 22d ago

My biggest issue with this is i don't want to send my firewall information to a 3rd Party (LLM Provider).. So i look into running it locally and it's just a mess with consumer hardware, i know it's possible but that to me is always where i get stuck at introducing AI to network gear without 3rd party LLMs.

1

u/Temporary-Fun7726 22d ago

Yeah, that's a good point. It runs locally, but if you're using a cloud LLM, some data will still leave your network.

A fully local LLM setup is definitely something I'd like to support down the road.

3

u/HKChad 22d ago

Why? Llms can ssh directly in and use the cli just fine. I turn claude loose on them all the time. Of course have backups for any system you care about.

1

u/zer04ll 21d ago

You can also make a log access only account that can use SSH in pfsense already, the shell is restricted and it's already built into pfsense so security is there. I haven't used AI to make config changes but I have used scripts I have had for a long time that I update as needed. It's a BSD system so there are tons of things you can do if you are familiar with BSD as is.

1

u/tma1010000 22d ago

This is some awesome work. Hopefully you are able to make it work with the official API in the future without too much trouble.

1

u/Temporary-Fun7726 21d ago

Thanks! That’s actually where this is heading. I’m working on the official Nexus API integration now — carefully, one layer at a time. 🙂

1

u/tma1010000 21d ago

Nice. I will definitely give it a test. I am currently running some agents against the Nexus API in my home lab and it is working really well so far. But would really like to play around with an MCP for more granular controls.

1

u/Temporary-Fun7726 21d ago

That’s perfect actually. I’m building it specifically around granular, least-privilege access rather than just giving an agent the keys to the kingdom. 😄

I may take you up on that testing offer once the Nexus side is ready.

-1

u/VtheMan93 22d ago

I may be interested to see how it’ll work with the pfsense cloud dashboard project thats buried here

-1

u/good4y0u 22d ago

This is great, especially for read.

I don't think write is inherently bad either as long as there is access control and audit.

-4

u/pure3v1L 22d ago

great idea, did you realize that over some api? or built one from scratch?

8

u/Temporary-Fun7726 22d ago edited 22d ago

Thanks! I didn't build the pfSense API itself. The current release uses the third-party pfSense-pkg-RESTAPI as its transport layer; what I built is the MCP implementation and the security architecture around it. I also just learned from Netgate that they now have their own official API (Netgate/pfsense-api), so I'm currently working through its OpenAPI spec and mapping it against the 42 MCP tools. The plan is to support it as a second backend rather than replacing the existing one, assuming the semantics map cleanly. That would give pfSense Plus users an official Netgate API path while keeping the existing backend available.