Netgate Discussion Forum
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Search
    • Register
    • Login
    Introducing Netgate Nexus: Multi-Instance Management at Your Fingertips.

    pfSense MCP server for AI agents — looking for security architecture feedback

    Scheduled Pinned Locked Moved Development
    3 Posts 1 Posters 284 Views 2 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • T Offline
      tomfrode
      last edited by

      Hi all,

      I've been developing an open-source MCP server for pfSense, and I'd like to get some feedback from people who know pfSense internals, networking and security better than I do.

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

      The project started with a fairly simple goal: allow AI agents such as Claude, ChatGPT and Codex to inspect — and eventually administer — pfSense through structured MCP tools.

      The more I worked on it, however, the more the security problem became the interesting part of the project.

      Giving an AI agent an API key with broad privileges and trusting the model not to do something dangerous didn't seem like an acceptable architecture for a firewall.

      So the project has evolved around a different question:

      How can an AI agent be allowed to administer a firewall without the security model depending on trusting the AI agent itself?

      Important: WRITE is not available yet

      This is deliberate.

      The current public MCP contract exposes:

      • 42 READ tools
      • 0 WRITE tools
      • 0/3 WRITE capabilities active
      • an empty WRITE endpoint allow-list

      So despite the longer-term goal of controlled firewall administration, an AI agent using the current server cannot modify pfSense through the MCP interface.

      I am intentionally trying to get the security architecture reviewed before exposing mutation capabilities, rather than adding WRITE first and trying to secure it afterwards.

      Security architecture

      The design separates two independent security axes.

      Capability posture

      • read_only
      • write_protected

      Anchor assurance

      • none
      • software
      • hardware_witness

      This distinction is important.

      For example:

      read_only + hardware_witness

      is a valid state — and is effectively where my hardened deployment is today.

      Provisioning stronger security infrastructure must never implicitly grant the AI additional capabilities.

      Hardware-backed anti-rollback protection

      For the hardened configuration I've implemented a TPM-backed anti-rollback witness.

      A separate host owns a TPM NV counter. A deliberately small, hardened systemd service exposes the required witness operation over mutually authenticated TLS.

      The MCP server can compare its persisted high-water mark against the hardware-backed counter.

      The security property I'm aiming for is that compromising or rolling back the MCP application's local state should not by itself be enough to recreate an older trusted authorization/security state.

      The TPM witness is deliberately independent of pfSense itself.

      The witness infrastructure is already operational, but again:

      this does not enable WRITE.

      Hardware assurance and capability authorization are separate concerns.

      How WRITE is intended to work

      WRITE is being designed to require substantially more than simply exposing POST/PUT/DELETE API calls.

      The architecture currently includes or plans:

      • explicit WRITE capability gating;
      • a separate WRITE endpoint allow-list;
      • endpoint risk classification;
      • Recovery Contracts around mutations;
      • precondition and postcondition verification;
      • bounded recovery semantics;
      • anti-rollback protection;
      • explicit operator authorization;
      • eventually fail-closed mutation behavior when required security evidence cannot be established.

      An important principle is:

      READ availability and WRITE authorization are separate.

      If the hardware witness becomes unavailable, that may eventually make mutation unsafe and therefore block WRITE.

      It should not unnecessarily make the firewall unobservable.

      Real-world READ-only testing

      I've also started using the server for actual pfSense troubleshooting rather than only synthetic tests.

      One recent example was an expired certificate.

      The MCP server could identify the expired certificate, inspect the other certificates, check users, RADIUS/EAP, ACME configuration and related state, and narrow the problem down considerably.

      But it couldn't determine one important fact:

      Which certificate was actually selected by the webConfigurator?

      The pfSense API coverage available to the server didn't expose that setting.

      Checking the pfSense GUI confirmed it.

      That exposed an interesting gap between API-visible state and the information an administrator can see in the WebGUI.

      Future idea: WebGUI Evidence Layer

      That experience led to a future architecture idea I'm currently exploring.

      The hierarchy would be roughly:

      1. pfSense API / structured MCP data first
      2. Allow-listed structured WebGUI extraction when the API cannot provide a required fact
      3. Screenshot/visual evidence only when structured extraction cannot reliably answer the question

      The important part is that this would not be unrestricted browser control for the AI.

      The browser would be treated as another security boundary.

      Pages, fields and allowed operations would need explicit constraints, and WebGUI-derived information would carry different provenance from API-verified information.

      Screenshot capture and screenshot retention would also be separate decisions; sensitive admin-interface screenshots should not automatically become permanent artifacts.

      This is currently only a roadmap/design idea — there is no WebGUI/browser capability in the MCP server today.

      What I'd really like feedback on

      I'm not primarily looking for "looks cool" feedback.

      I'd much rather have people familiar with pfSense and firewall security try to break the assumptions behind the design.

      In particular:

      • What threats am I missing?
      • Does the remote TPM witness provide a useful security boundary, or am I overestimating what it buys me?
      • Are there pfSense-specific failure modes I should design around?
      • How would you classify pfSense WRITE operations by risk?
      • Are Recovery Contracts a sensible model for firewall mutations?
      • Are there operations that an AI agent simply should never be allowed to perform?
      • Is the API-first → structured WebGUI → visual evidence hierarchy reasonable?
      • What should happen if the security state and the firewall state disagree?
      • What would you expect from installation, provisioning, downgrade and recovery?
      • Where does this architecture become too complicated to operate safely?

      And perhaps the question I'm most interested in:

      If you were reviewing this before allowing an AI agent to make changes to your own pfSense firewall, what would make you reject the design?

      The project is intentionally conservative at this stage.

      WRITE is still unavailable.

      I'd rather discover that an assumption, trust boundary or recovery mechanism is wrong while the public interface is still 42 READ / 0 WRITE than discover it after giving an AI agent mutation capabilities.

      The repository contains the implementation, tests, ADRs and security design documentation:

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

      Any criticism, design ideas, pfSense-specific edge cases or security concerns would be very welcome.

      1 Reply Last reply Reply Quote 1
      • T Offline
        tomfrode
        last edited by

        Update — since the original post: the WRITE path described above is now built, tested, and shipped (still off by default). Looking for the same kind of hostile review on what actually got implemented.

        Quick recap of where this stood originally: 42 read-only tools, zero write capability active, capability-posture/anchor-assurance split designed but not exercised. Since then, the WRITE side of that design has actually been implemented and run against real (disposable, LAB-only) hardware, and the project is now publicly released — v0.4.2 on PyPI and GitHub.

        What's unchanged: the default MCP surface is still exactly 42 READ tools, 0 reachable WRITE capabilities. That hasn't moved and isn't going to casually.

        What's new:

        • One WRITE capability is now implemented and verified=True: set_firewall_alias_description_v1 — a deliberately low-blast-radius operation (alias description field only). It stays completely unreachable unless an operator explicitly sets PFSENSE_PROFILE=write_protected; the default profile still exposes zero write-shaped tools.
        • The full path — off-host Ed25519-signed authorization → RecoveryContract → independent, separately-signed confirmation → sealed execution → authoritative read-back — has been exercised end-to-end, twice, against the isolated LAB pfSense appliance (never production/home pfSense).
        • Authorization is single-use (consumed exactly once) and execution re-validates live state immediately before mutating, refusing on staleness or a concurrent change.
        • The authorization signer and the confirmation signer are two distinct authorities, so one compromised signing key alone can't push a mutation through.
        • A dedicated least-privilege pfSense identity was provisioned and used for both runs — never the admin account — holding exactly the four REST privileges the operation needs (api-v2-firewall-aliases-get, api-v2-firewall-alias-patch, api-v2-status-system-get, api-v2-system-hasync-get), independently re-verified before and after. A fifth, narrowly-scoped bootstrap privilege was needed once to let that identity generate its own API key; it was granted, used, and revoked before the identity was used for anything else.
        • RecoveryContract behavior is now exercised in live end-to-end execution, while fail-closed reconciliation and ambiguous-outcome handling are covered by production-bound tests against the real executor/adapter path rather than being design-only claims.
        • The TPM-backed anti-rollback witness described in the original post was exercised against the physical hardware both times (witness advanced 2→3, then 3→4), independently re-read and cross-checked against the persisted store state after each run — no divergence either time.
        • The temporary description written to the LAB alias during the first run was subsequently reverted back to its original value through the same controlled path (same identity, same authorization/confirmation ceremony, same execution/read-back), not a manual fix.

        Full evidence chain, exact field-by-field mapping, and both ceremonies' verification steps: ADR-026-first-write-capability-adapter.

        Not claiming: no independent security audit, no formal verification, not "the most secure" anything, not unhackable, not production-safe in every environment. Two live executions against a lab appliance plus test coverage — no adversarial review from anyone but me yet, which is the point of this update.

        Still looking for review on, specifically:

        • Whether the 4-privilege REST scope is actually minimal for this operation, or if the REST API package supports something narrower I've missed.

        • pfSense-side timing I might not have accounted for — config reload, HA/CARP sync, config.xml locking — anything that could put the read-back step in a race.

        • Replay/TOCTOU angles on the authorization → execution gap.

        • Whether the RecoveryContract/reconciliation model actually holds up for firewall-style mutations, or where it'd break under a real network partition / mid-mutation reboot.

        • Whether the TPM witness assumptions are sound, or what you'd want proven that isn't in the ADR.

        • Any other pfSense-specific failure mode this architecture hasn't accounted for.

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

        • PyPI (v0.4.2): https://pypi.org/project/pfsense-mcp-server/0.4.2/

        • ADR-026: https://night4me.github.io/pfsense-mcp-server/adr/ADR-026-first-write-capability-adapter/

        1 Reply Last reply Reply Quote 0
        • T Offline
          tomfrode
          last edited by

          pfsense-mcp-server v1.0.0 is now available.

          This is the first stable release, with most of the work since v0.9 focused on hardening, documentation, setup/UX, and end-to-end validation rather than adding more API surface.

          The default MCP surface remains deliberately read-only:

          95 pfSense read tools
          2 guidance tools
          0 write tools exposed by default

          v1.0 also includes a much simpler guided setup, improved TLS/private-CA handling, secure API-key-file configuration, automatic MCP client configuration for Codex and Claude Desktop, clearer diagnostics, and a full security/stability audit.

          I also tested the complete clean-room setup on a fresh Ubuntu VM against a real pfSense lab. The generated Codex configuration was then used directly by Codex CLI to connect through MCP and perform real pfSense read operations. Asking Codex to change pfSense settings was correctly refused because the active MCP profile exposed zero write tools.

          The project is still designed around the same principle: useful AI access to pfSense without turning the MCP server into an unrestricted API proxy.

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

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

          Feedback, bug reports and testing against different pfSense installations are very welcome.

          1 Reply Last reply Reply Quote 0
          • First post
            Last post
          Copyright 2026 Rubicon Communications LLC (Netgate). All rights reserved.
          Privacy Policy · Cookie Policy