Please report suspected vulnerabilities privately via GitHub Security Advisories (the Security tab of this repository) rather than opening a public issue.
This library is a thin JSON-RPC 2.0 transport. The server executes procedures that
you register, so the security of a deployment depends heavily on how it is wired up.
The v1.5 release hardened several concrete issues (see CHANGELOG.md) and this document
records the audit findings and the recommended way to run the server safely.
- Redirect credential leakage (client). The client no longer follows HTTP redirects,
so
Authorization/Cookieheaders are never resent to a redirect target. - Magic-method invocation (server). Procedure names starting with
__can no longer be dispatched to objects registered withwithObject(). - IP allowlist correctness (server).
HostValidatornow fails closed on malformed input and uses strict comparisons. - Auth timing side channels (server). Username lookup and password comparison are constant-time.
These behaviours are opt-in (default off) to preserve backward compatibility; enabling them is recommended for production. They are candidates for secure-by-default in a future major version.
-
Hide internal exception messages. By default, an exception thrown inside a procedure that is not registered as a "local exception" has its message and code relayed to the client, which can leak database errors, file paths or stack context. Enable masking:
$server->withInternalErrorMasking(); // unknown exceptions become -32603 "Internal error"
Masking also suppresses the
datamember of-32602 Invalid paramserrors, because anyInvalidArgumentExceptionthrown by a procedure carries its message there.You can still expose intended client-facing errors by throwing
JsonRPC\Exception\ResponseException(which carries its own message/code/data), or keep an exception server-side with$server->withLocalException(MyException::class). -
Bound the batch size. A batch may contain an unbounded number of calls. Cap it:
$server->withBatchLimit(50); // larger batches are rejected with -32600
Also cap the raw request body at the web-server/PHP layer (
post_max_size,client_max_body_size, a reverse-proxy limit) to reject oversized payloads before decoding. -
Expose only intended procedures. Prefer
getProcedureHandler()->withCallback()or->withClassAndMethod(), which bind explicit names, over->withObject($service).withObject()exposes every public method of the instance (and its parents) as an RPC endpoint (magic__methods excepted). If you use it, attach a dedicated facade object that contains only the methods you intend to publish. -
IP allowlisting is IPv4-only and trusts
REMOTE_ADDR. CIDR matching supports IPv4 only. Behind a reverse proxy,REMOTE_ADDRis the proxy's address, so the allowlist is only meaningful if enforced at the proxy. The library intentionally does not trustX-Forwarded-For. -
Always use TLS for HTTP Basic authentication. Credentials are Base64-encoded, not encrypted.