{
  "schema": "leumas.docs.page/1",
  "id": "pkg:@leumas/security",
  "slug": "packages/security",
  "kind": "capabilities",
  "bucket": "package",
  "title": "@leumas/security",
  "name": "@leumas/security",
  "eyebrow": null,
  "chip": null,
  "summary": "How every Leumas backend defends itself, declared once — the programmable security policy (session · cors · rate limits · body limits · http) plus the middleware that enforces it, mounted in the one...",
  "keywords": [
    "security",
    "defends",
    "cors",
    "limits",
    "backend",
    "security api",
    "leumas security",
    "how to use security"
  ],
  "audience": "both",
  "funnel": {
    "product": null,
    "cta": null
  },
  "body": "# @leumas/security\n\nHow every Leumas backend defends itself, declared once: **one policy file, one `applySecurity()` call.**\n\nBefore this package the same stack was hand-rolled per service and the copies had drifted —\n`http://localhost:5173` was the CORS default in five separate files, `express.json({limit:'2mb'})`\nappeared in two servers, and the two backends that terminate HTTP alongside the API (the Imperium\nhost and the compute worker) shipped **no security headers at all**. Meanwhile the API constructed a\nfresh body parser on every request and never swept a single rate-limit bucket.\n\n## Use it\n\n```js\nimport express from 'express';\nimport { applySecurity, applyServerTimeouts, staticCacheOptions } from '@leumas/security';\n\nconst app = express();\nconst security = applySecurity(app, { json: express.json, servesSpa: Boolean(dist) });\n\nmountYourAuth(app);                       // between the stack and the backstop — see below\napp.get('/health', …);                    // before the backstop, so a probe is never throttled\nsecurity.mountBackstop();\n\napp.use('/leviathan', security.lanes.llm, leviathanRouter);   // a lane is an array; express takes it\n\napplyServerTimeouts(server);                                  // on the http.Server, not the app\napp.use(express.static(dist, { index: false, ...staticCacheOptions() }));\n```\n\n`json` is **injected** rather than imported, so this package never depends on express — and injecting\nit is also what lets the body parsers be built once, at boot, instead of per request.\n\n## Order is the point\n\nEvery service that hand-rolled this got a different order, and the order is where the bugs are, not\nthe individual options. `applySecurity` mounts:\n\n1. `x-powered-by` off\n2. **helmet** — headers must be set before anything can answer, including a 429\n3. **compression** — must wrap `res.write` before a route writes, and must skip SSE\n4. **CORS**, public lane then credentialed lane\n5. **body parsers** — after CORS, so a rejected preflight never reads a body\n6. *(the caller mounts auth here)*\n7. **the per-IP backstop** — last, after auth, and after `/health`\n\nThe caller mounts auth between 5 and 7 because only the caller knows what auth means for it: the API\nhas sessions, the compute worker has a shared key, the Imperium host has neither.\n\n## The three traps this encodes\n\nEach of these has already cost this repo a live defect. They are handled here so no service has to\nrediscover them.\n\n**CORS cannot be one layer.** `cors()` emits `Access-Control-Allow-Credentials: true`\n*unconditionally* — even for an origin it does not allow. So the public-catalog paths cannot simply\njoin the allowlist; they need their own un-credentialed wildcard layer mounted **first**, and the\ncredentialed layer has to **skip those same paths**. When both ran, responses carried `Allow-Origin: *`\n*and* `Allow-Credentials: true` — a pair browsers reject — and the catalog silently stopped being\nreadable cross-origin, which is the one thing the wildcard existed for. `'*'` inside `origins` is\nhandled as the literal wildcard, because `cors()` otherwise compares it for exact equality and matches\nnothing.\n\n**Compression buffers SSE.** `compression`'s default filter asks the `compressible` package, which\nanswers *true* for `text/event-stream` because it matches `text/*`. Compressing a live stream buffers\nit: every feed in the product — automation, surveillance detections, release build logs, the serial\nmonitor — appears to hang and then arrive all at once. It looks like a network fault, not a setting.\nExcluded unconditionally, along with bodies that already set their own `Content-Encoding`.\n\n**Some routes must not be parsed at all.** A `null` in `body.byPrefix` means *skip* — Stripe verifies\nits signature over the **unmodified** bytes, and a parser anywhere above the webhook breaks every one\nof them with an error that reads like a key mismatch.\n\n## The policy\n\nDefaults → repo `ops/config/security.json` → `<dataRoot>/security.json` → `LEUMAS_SECURITY_CONFIG`\n→ env. Cached ~5s, so an edit applies with **no restart**; a parse error keeps the last good value\nrather than failing open. Five sections: `session`, `cors`, `limits`, `body`, `http`.\n\n**Nothing in it is a credential.** Cookie name, cookie domain and `JWT_SECRET` stay in env, because\nthey are deployment *identity* rather than *policy* — and this file is checked into the repo and\neditable from Studio. `smoke-security-stack.mjs` asserts that boundary rather than trusting it.\n\n## Verify\n\n```\npnpm smoke:security          # access + integrity + stack\npnpm smoke:security-stack    # headers, the CORS pair, SSE-safe compression, per-prefix bodies\npnpm smoke:session           # the session half of the same policy file\npnpm check:routes            # the mounted layer list, per role\n```\n",
  "source": {
    "path": "shared/packages/security/README.md",
    "blobSha": "",
    "commit": "",
    "committedAt": "",
    "provenance": "no-git",
    "bytes": 4994,
    "hash": "ea670f40c54114d87cf9a98340b611eb1dc3e54b"
  },
  "urls": {
    "html": "/p/packages/security",
    "json": "/docs/packages/security.json",
    "md": "/docs/packages/security.md"
  },
  "links": {
    "composes": [],
    "usedBy": [
      "pkg:@leumas/auth",
      "pkg:@leumas/connectors",
      "pkg:@leumas/imperium-server"
    ],
    "product": [
      "pkg:@leumas/admin",
      "pkg:@leumas/studio"
    ],
    "howTo": [],
    "skills": [
      "skill:leumas-studio"
    ]
  },
  "exports": {
    "total": 100,
    "component": 15,
    "hook": 0,
    "helper": 85,
    "names": [
      {
        "n": "BODY_DEFAULTS",
        "k": "component"
      },
      {
        "n": "BODY_DEFAULTS",
        "k": "component"
      },
      {
        "n": "COMPACT_AFTER_MS",
        "k": "component"
      },
      {
        "n": "CORS_DEFAULTS",
        "k": "component"
      },
      {
        "n": "CORS_DEFAULTS",
        "k": "component"
      },
      {
        "n": "CSRF_DEFAULTS",
        "k": "component"
      },
      {
        "n": "CSRF_DEFAULTS",
        "k": "component"
      },
      {
        "n": "DEFAULT_DAY_DAYS",
        "k": "component"
      },
      {
        "n": "DEFAULT_HOUR_DAYS",
        "k": "component"
      },
      {
        "n": "HTTP_DEFAULTS",
        "k": "component"
      },
      {
        "n": "HTTP_DEFAULTS",
        "k": "component"
      },
      {
        "n": "LIMIT_DEFAULTS",
        "k": "component"
      },
      {
        "n": "LIMIT_DEFAULTS",
        "k": "component"
      },
      {
        "n": "SESSION_DEFAULTS",
        "k": "component"
      },
      {
        "n": "SESSION_DEFAULTS",
        "k": "component"
      },
      {
        "n": "applySecurity",
        "k": "helper"
      },
      {
        "n": "applyServerTimeouts",
        "k": "helper"
      },
      {
        "n": "bodyParser",
        "k": "helper"
      },
      {
        "n": "bodyParser",
        "k": "helper"
      },
      {
        "n": "bodyPolicy",
        "k": "helper"
      },
      {
        "n": "bodyPolicy",
        "k": "helper"
      },
      {
        "n": "byUserThenIp",
        "k": "helper"
      },
      {
        "n": "byUserThenIp",
        "k": "helper"
      },
      {
        "n": "clearRateLimit",
        "k": "helper"
      },
      {
        "n": "clearRateLimit",
        "k": "helper"
      },
      {
        "n": "clientIp",
        "k": "helper"
      },
      {
        "n": "clientIp",
        "k": "helper"
      },
      {
        "n": "compactRequestRollups",
        "k": "helper"
      },
      {
        "n": "compressionLayer",
        "k": "helper"
      },
      {
        "n": "compressionLayer",
        "k": "helper"
      },
      {
        "n": "corsLayers",
        "k": "helper"
      },
      {
        "n": "corsLayers",
        "k": "helper"
      },
      {
        "n": "corsPolicy",
        "k": "helper"
      },
      {
        "n": "corsPolicy",
        "k": "helper"
      },
      {
        "n": "createRequestRollup",
        "k": "helper"
      },
      {
        "n": "csrfOriginGuard",
        "k": "helper"
      },
      {
        "n": "csrfOriginGuard",
        "k": "helper"
      },
      {
        "n": "csrfPolicy",
        "k": "helper"
      },
      {
        "n": "csrfPolicy",
        "k": "helper"
      },
      {
        "n": "drainRollup",
        "k": "helper"
      },
      {
        "n": "envPinnedFields",
        "k": "helper"
      },
      {
        "n": "envPinnedFields",
        "k": "helper"
      },
      {
        "n": "envPinnedSessionFields",
        "k": "helper"
      },
      {
        "n": "envPinnedSessionFields",
        "k": "helper"
      },
      {
        "n": "foldTail",
        "k": "helper"
      },
      {
        "n": "histogramEdges",
        "k": "helper"
      },
      {
        "n": "httpPolicy",
        "k": "helper"
      },
      {
        "n": "httpPolicy",
        "k": "helper"
      },
      {
        "n": "jsonCacheHeaders",
        "k": "helper"
      },
      {
        "n": "limitsPolicy",
        "k": "helper"
      },
      {
        "n": "limitsPolicy",
        "k": "helper"
      },
      {
        "n": "memoryStore",
        "k": "helper"
      },
      {
        "n": "memoryStore",
        "k": "helper"
      },
      {
        "n": "normalizeBodyPolicy",
        "k": "helper"
      },
      {
        "n": "normalizeBodyPolicy",
        "k": "helper"
      },
      {
        "n": "normalizeCorsPolicy",
        "k": "helper"
      },
      {
        "n": "normalizeCorsPolicy",
        "k": "helper"
      },
      {
        "n": "normalizeCsrfPolicy",
        "k": "helper"
      },
      {
        "n": "normalizeCsrfPolicy",
        "k": "helper"
      },
      {
        "n": "normalizeHttpPolicy",
        "k": "helper"
      },
      {
        "n": "normalizeHttpPolicy",
        "k": "helper"
      },
      {
        "n": "normalizeLimitsPolicy",
        "k": "helper"
      },
      {
        "n": "normalizeLimitsPolicy",
        "k": "helper"
      },
      {
        "n": "normalizeSessionPolicy",
        "k": "helper"
      },
      {
        "n": "normalizeSessionPolicy",
        "k": "helper"
      },
      {
        "n": "normalizeTrustProxy",
        "k": "helper"
      },
      {
        "n": "normalizeTrustProxy",
        "k": "helper"
      },
      {
        "n": "rateLanes",
        "k": "helper"
      },
      {
        "n": "rateLanes",
        "k": "helper"
      },
      {
        "n": "rateLimit",
        "k": "helper"
      },
      {
        "n": "rateLimit",
        "k": "helper"
      },
      {
        "n": "recordRequest",
        "k": "helper"
      },
      {
        "n": "redepositRollup",
        "k": "helper"
      },
      {
        "n": "reloadSecurityConfig",
        "k": "helper"
      },
      {
        "n": "reloadSecurityConfig",
        "k": "helper"
      },
      {
        "n": "requestStats",
        "k": "helper"
      },
      {
        "n": "requestTiming",
        "k": "helper"
      },
      {
        "n": "resetRequestStats",
        "k": "helper"
      },
      {
        "n": "runRequestRetention",
        "k": "helper"
      },
      {
        "n": "saveSecurityPolicy",
        "k": "helper"
      },
      {
        "n": "saveSecurityPolicy",
        "k": "helper"
      },
      {
        "n": "saveSessionPolicy",
        "k": "helper"
      },
      {
        "n": "saveSessionPolicy",
        "k": "helper"
      },
      {
        "n": "securityConfig",
        "k": "helper"
      },
      {
        "n": "securityConfig",
        "k": "helper"
      },
      {
        "n": "securityConfigPaths",
        "k": "helper"
      },
      {
        "n": "securityConfigPaths",
        "k": "helper"
      },
      {
        "n": "securityHeaders",
        "k": "helper"
      },
      {
        "n": "securityHeaders",
        "k": "helper"
      },
      {
        "n": "sessionPolicy",
        "k": "helper"
      },
      {
        "n": "sessionPolicy",
        "k": "helper"
      },
      {
        "n": "sharedStore",
        "k": "helper"
      },
      {
        "n": "sharedStore",
        "k": "helper"
      },
      {
        "n": "startSweeper",
        "k": "helper"
      },
      {
        "n": "startSweeper",
        "k": "helper"
      },
      {
        "n": "staticCacheOptions",
        "k": "helper"
      },
      {
        "n": "stopPolicyRefresh",
        "k": "helper"
      },
      {
        "n": "stopPolicyRefresh",
        "k": "helper"
      },
      {
        "n": "stopSweeper",
        "k": "helper"
      },
      {
        "n": "stopSweeper",
        "k": "helper"
      }
    ]
  }
}
