# Local security

> Security requirements for LMSP services, with loopback binding, pairing and bearer tokens, scopes, Origin and Host checks against malicious web pages, LAN mode and logging rules.

Source: https://madeforagent.com/lmsp/1.0/security/
Language: en
Specification: LMSP 1.0 (draft)
Updated: 2026-11-08

## 10.1 Baseline {#baseline}

Listening only on localhost is not absolute security: a malicious web page can still try to reach local ports. LMSP therefore combines several measures.

- A service **MUST** bind to the loopback addresses by default. It **MUST NOT** listen on `0.0.0.0`, or on any other non-loopback address, unless LAN mode is enabled ([section 10.5](https://madeforagent.com/lmsp/1.0/security.md#lan)).
- On first run, a service **SHOULD** generate a high-entropy random service secret, and use it, rather than any built-in default, to issue and verify tokens.
- Every request to the core interface **MUST** carry a valid bearer token, except for the bootstrap endpoints listed in [section 4.2](https://madeforagent.com/lmsp/1.0/endpoints.md#conventions). Coming from loopback is never enough on its own.

## 10.2 Pairing and tokens {#pairing}

A client gets its own bearer token with a local pairing code. The user asks the service to show a pairing code, in whatever way the service offers, and the client submits it:

```http
POST /lmsp/v1/pair
Content-Type: application/json
```

```json
{
  "client_name": "example-client",
  "pairing_code": "K7QD-4M2X",
  "scopes": ["inference"]
}
```

| Request field | Meaning |
| --- | --- |
| `client_name` | Display name of the client, shown to the user. |
| `pairing_code` | The code the user obtained from the service. |
| `scopes` | Optional list of requested scopes. Defaults to `["inference"]`. |

The service answers with a token. The `token_type` is always `Bearer`:

```json
{
  "client_id": "cli_01J8MAT3W6X9B2D5F8H1K4N7QZ",
  "access_token": "lmsp_example_3f9a1c52e7d84b60",
  "token_type": "Bearer",
  "scopes": ["inference"]
}
```

The client then sends `Authorization: Bearer <token>` with every request.

- A pairing code **MUST** be single-use and **SHOULD** expire within 5 minutes. It **SHOULD** carry at least 40 bits of entropy. A service **MUST** rate-limit failed attempts. A wrong or expired code is answered with `401` and `unauthorized`.
- Tokens are independent per client, so the user can revoke one client without affecting the others. A service **SHOULD** let the user list and revoke paired clients.
- A client **SHOULD** keep its token in the operating system keychain or credential manager. A service **SHOULD** store only a hash of each token.
- A missing, invalid or revoked token is answered with `401`, `unauthorized` and a `WWW-Authenticate: Bearer` header. A valid token that lacks the scope an endpoint needs is answered with `403` and `forbidden`.

## 10.3 Scopes {#scopes}

Permissions are split into separate scopes. Downloading models, deleting models and executing tools never ride on the inference scope.

| Scope | Allows |
| --- | --- |
| `inference` | Reading the model catalog, creating responses and tasks, and reading and cancelling the client's own tasks. |
| `models:manage` | Loading and unloading models. |
| `models:install` | Reserved. Downloading and deleting models. |
| `tools:execute` | Reserved. Executing tools on the service side. |

Tasks and stored responses belong to the client that created them. A service **SHOULD** answer a request from another client as if they did not exist (`task_not_found` or `response_not_found`).

## 10.4 Browser and network protections {#browser}

- A service **MUST** reject cross-origin browser requests by default, and allow only `Origin` values that are explicitly configured. A request with any other `Origin` is answered with `403` and `forbidden`.
- When an origin is allowed, the service answers its CORS preflight requests and sends `Access-Control-Allow-Origin` with that exact origin, never with `*`.
- A service **MUST** validate the `Host` header, to prevent DNS rebinding. It accepts only host names it serves: the loopback names and addresses, plus any names configured for LAN mode. Any other value is answered with `403` and `forbidden`.

## 10.5 LAN mode {#lan}

LAN mode means listening beyond the loopback addresses.

- A service **MUST NOT** enable LAN mode unless the user explicitly turns it on.
- In LAN mode a service **MUST** require authentication, and **SHOULD** also enable TLS. A client **SHOULD NOT** send a token over plain HTTP to a non-loopback address unless the user explicitly allows it.
- mDNS advertisement is allowed only in LAN mode, when the user has also turned on LAN discovery ([section 3.2](https://madeforagent.com/lmsp/1.0/discovery.md#mdns)).

## 10.6 Logging and privacy {#logging}

- Model paths, logs, prompts and generated content **MUST NOT** appear in mDNS advertisements.
- By default, a service **SHOULD** log metadata only (times, endpoints, status codes, ids, token counts and durations). It **SHOULD NOT** log full prompts or generated content.
- Health responses and error details **MUST NOT** contain model paths, prompts, access tokens or other sensitive information.
