← All Docs

Logs and security

PolicyLayer keeps two audit streams:

  • Proxy logs for runtime MCP requests through a server.
  • Admin audit events for state-changing dashboard actions.

Proxy logs

The Logs tab on a server shows authenticated proxy POST requests that reach the JSON-RPC request pipeline. Requests rejected before grant authentication, and batch requests rejected before the single-request pipeline, do not create proxy log rows.

Each proxy log records:

  • Grant label and ID.
  • Server.
  • JSON-RPC method and tool name for tools/call.
  • Policy and policy version, when a policy was attached.
  • Decision outcome, rule, and message.
  • Upstream HTTP status and latency, when the request reached upstream.
  • Timestamp and request ID.
  • Top-level argument keys only.

viewer, policy_manager, and admin can read proxy logs.

Redaction

PolicyLayer does not store tool argument values in proxy logs. It stores only top-level argument keys, sorted by name.

That means a log can show that a call included amount and currency, but not the values passed for those fields. If you need value-level enforcement, write a policy predicate. The predicate inspects the value at request time; the log records the rule that fired, not the value.

Decision rules

The decision rule tells you what allowed or denied the call.

Common shapes:

  • JSON Pointers for predicates and limits, such as /tools/create_charge/deny_if/args.amount-gt or /all_tools/limits/calls-per-minute.
  • (no policy) when a grant has no policy attached.
  • (hidden) when a hidden tool is called.
  • (default deny) when a policy uses default: deny and the tool is not listed.
  • Empty for allowed calls with no firing rule.

The decision message is the user-facing denial message, either from the policy’s on_deny field or from the policy engine.

Quota rollbacks

PolicyLayer reserves quota before forwarding a tools/call that has an applicable limit. If the proxy can inspect the upstream response synchronously and the call failed, PolicyLayer rolls the reservation back and records the outcome as allowed_rolled_back.

Streaming responses and 202 Accepted responses are treated as accepted upstream work, because the proxy does not get a synchronous final result to inspect.

Admin audit events

The admin audit log records state-changing dashboard actions, including:

  • Server creation, deletion, and header changes.
  • OAuth connect, reconnect, and disconnect actions.
  • Grant creation, reveal, rotation, revocation, and policy attachment changes.
  • Policy creation, edits, and deletion.
  • Member invites and role changes.

The admin audit log is visible only to admin users.

Credential storage

PolicyLayer encrypts stored credential material before writing it to Postgres:

  • Upstream OAuth access tokens, refresh tokens, client IDs, and client secrets.
  • Static upstream headers, including API keys and tenant headers.
  • Encrypted grant tokens used when an admin clicks Reveal.

Encryption uses AES-256-GCM with versioned keys. ENCRYPTION_KEY_V<N> defines available keys, and ENCRYPTION_KEY_PRIMARY selects the version used for new writes. Existing ciphertexts carry their key version, so PolicyLayer can still decrypt old rows during key rotation.

Grant tokens are also hashed. The proxy authenticates grants by token hash lookup; the encrypted copy supports admin reveal flows.

Proxy header handling

PolicyLayer consumes the incoming Authorization header as the grant token. It does not forward that header upstream. If the upstream needs credentials, the proxy injects the server’s configured OAuth token or static headers.

The proxy also strips incoming Cookie headers before forwarding requests, and strips upstream Set-Cookie headers before returning responses to the client.

Upstream URL safety

PolicyLayer validates upstream URLs when a server is saved and again when the proxy dispatches a request.

It accepts HTTPS URLs by default, rejects URLs with embedded usernames or passwords, and uses a safe HTTP client for outbound calls. By default, blocked destinations include loopback, private, link-local, multicast, unspecified, and cloud metadata addresses.

Self-hosted deployments can allow private upstreams with MCP_ALLOW_PRIVATE_UPSTREAMS=true. Even then, public http:// upstreams and cloud metadata addresses are rejected.

Grant scope

A grant belongs to one server. The proxy URL includes the server UUID, and the proxy rejects a request if the URL’s server UUID does not match the server bound to the bearer token.

Rotating or revoking one grant does not rotate or revoke other grants on the same server.

Account access

Dashboard users sign in with Google OAuth, GitHub OAuth, or magic-link email. PolicyLayer does not store user passwords.

Reporting

Send security reports to security@policylayer.com.

// GET IN TOUCH

Have a question or want to learn more? Send us a message.

Message sent.

We'll get back to you soon.

// REQUEST EARLY ACCESS

We're letting people in as fast as we can.

You're in the queue.

We'll be in touch as soon as we can let you in.