ecluse:ecluse-core
Safe HaskellNone
LanguageGHC2021

Ecluse.Core.Security

Description

Outbound-request and response-bound guards for the proxy's data plane.

Écluse builds outbound HTTP requests from two untrusted sources -- __client-supplied package identifiers (the request path) and upstream-supplied artifact locations__ (a packument's dist.tarball) -- and then parses whatever an upstream returns. This module is the pure guard layer that keeps those steps from being steered or exhausted by hostile input. It defends three boundaries:

  • Where the proxy fetches. isAllowedUpstreamHost restricts outbound fetches to the configured upstream hosts, and isBlockedTarget rejects internal address ranges (cloud instance metadata, loopback, RFC1918) that the proxy's network position can otherwise reach. Together they are the SSRF gate: a target must be both on the allowlist and not an internal address.
  • How an upstream URL is derived. upstreamUrlFor builds an artifact/metadata URL from a configured base URL and an already-parsed PackageName, never from raw client path segments, re-checking each name component with the router's own safety rule so traversal, encoded slashes, or an absolute URL cannot change the target.
  • How much an upstream may cost. A Limits budget plus boundedRead (abort a streamed body past maxBodyBytes) and checkVersionCount / checkNestingDepth (reject an oversized or deeply-nested parsed document) bound algorithmic-complexity DoS from a hostile or compromised upstream. Every limit fails closed: exceeding one yields Left, never a truncated or partial result.

The functions are pure and total; the streamed-body guard (boundedRead) is polymorphic over the producing monad so the streaming data plane can run it in IO while tests drive it purely. They are primitives: the fetch and serve layers compose them at the boundary (see docs/architecture/registry-model.md → "Registry Abstraction", docs/architecture/web-layer.md, and docs/architecture/hosting.md → "URL rewriting"). Path-component safety is shared with the router's Ecluse.Core.Server.Route (isSafeComponent); the threat model these guards answer is recorded there too.

Documentation