ezBookkeeping IP allowlist falls to a single spoofed header
A advisory published on 9 November 2026 says attackers can defeat the MCP and API token IP allowlist in ezBookkeeping by adding one request header.
By The Agentic Times ·

A critical authentication bypass in ezBookkeeping, the self-hosted personal finance application from developer mayswind, lets a remote attacker from any IP address defeat the operator-configured source-IP allowlist that guards its MCP and API token endpoints. The flaw was published as GitHub advisory GHSA-wchh-mrv2-5h4q, tracked as CVE-2026-86041, on 9 November 2026. According to the advisory, the bypass needs nothing more than a single X-Forwarded-For header containing an allowlisted address.
MCP, the Model Context Protocol, is the interface AI agents use to call tools and read data from an application. Operators of ezBookkeeping can restrict which source addresses may reach that interface, and the separate API token surface, using the mcp_allowed_remote_ips and api_token_allowed_remote_ips settings. The advisory describes this as an explicitly advertised security control.
The cause is a default setting rather than a logic error. The advisory states that the web server builds its router with gin.New() and never calls SetTrustedProxies, which leaves the gin web framework's default trusted-proxy range at 0.0.0.0/0 and ::/0 — in other words, every proxy on the internet is trusted. As a result, the framework's ClientIP() function returns whatever address the caller supplies in the X-Forwarded-For header, rather than the real connecting address. The advisory adds that the application's own WebContext type embeds the gin context and does not override ClientIP().
Both allowlist middlewares compare the operator's permitted ranges against that attacker-controlled value, according to the advisory. The researcher published a runtime test as proof. In the published output, a request with no header from address 1.2.3.4 is correctly blocked with a 400 response, while the same request carrying X-Forwarded-For: 10.0.0.1 returns a 200 and a client IP of 10.0.0.1. Against a live instance configured with mcp_allowed_remote_ips=10.0.0.1, the advisory shows a plain request to the /mcp path returning 403 and the same request with the forged header passing the IP gate.
The second effect is on record-keeping. The advisory says the same forged value is written to the CreatedIp field of new transactions and to the access log, so one header both opens the gate and forges attribution. It describes this as destroying non-repudiation, because every logged action appears to come from the trusted host rather than the attacker, and the attacker's real address never appears in any record.
The advisory is careful about the limits of the attack. The MCP and API token actions themselves still require a valid token, it says, so the issue neutralises the compensating IP control rather than the JWT authentication layer. Operators who rely on the allowlist as a second line of defence behind token authentication are the ones most exposed; those who treat it as the only barrier have, on the advisory's account, no barrier at all.
The advisory lists the affected package as the Go module github.com/mayswind/ezbookkeeping. At the time the advisory was published it was recorded as reported, and no fixed version is named in the advisory text. The underlying pattern — a proxy-aware framework trusting forwarded headers by default — is not specific to this product, and the advisory points to the missing SetTrustedProxies call as the single point where the behaviour could be corrected.
Sources
- github.comhttps://github.com/advisories/GHSA-wchh-mrv2-5h4q
