Skip to content

Security: keaz/aicore-web

Security

docs/security.md

Security

This document defines the production security posture for aicore-web. It is a framework hardening guide, not an application security review substitute.

Deployment Assumptions

  • The GA runtime target is Linux behind a production reverse proxy or load balancer.
  • Terminate TLS at the proxy unless the application explicitly owns TLS.
  • Forward only trusted proxy headers, and normalize or drop user-supplied forwarding headers at the edge.
  • Configure proxy request-line, header-count, header-size, body-size, idle-timeout, and total-timeout limits at or below the service limits.
  • Run one HTTP request per accepted connection at the framework layer; keep-alive and pipelining are proxy responsibilities for now.

Threat Model

Request parsing risks include malformed request lines, invalid targets, truncated bodies, ambiguous Content-Length, unsupported transfer encodings, malformed chunk frames, and oversized parser buffers. Socket parser failures close the connection deterministically; dispatch-level violations return JSON error responses.

Header handling risks include CRLF injection, unsafe header names, oversized header names or values, repeated headers, and request smuggling through conflicting length metadata. The framework lowercases header keys, rejects unsafe controls, rejects Transfer-Encoding plus Content-Length, rejects invalid or mismatched Content-Length, rejects unsupported transfer encodings, and rejects configured header-count/name/value limit violations.

Path handling risks include traversal, backslash normalization ambiguity, CR/LF injection, and oversized targets. Safe paths are enabled by default and reject paths that do not start with /, contain .., contain \, or contain CR/LF.

Body parsing risks include oversized JSON/XML payloads, invalid JSON, validation bypass, unsafe XML names, nested XML that the limited object parser does not support, entity expansion, DTDs, and parser error disclosure. Body size is checked before handler dispatch; JSON/XML binders return framework JSON errors; XML tag names are constrained by aicore_web_xml.xml.is_safe_name, XML field values are bounded, and custom entities/DTDs are rejected.

Filter risks include unexpected execution order and security filters being registered after application filters. Filters have explicit unique numeric order values; duplicate orders are rejected. Register security filters at low order values so request rejection happens before application filters and secure headers run late in the response path. Server preflight rejects run before filters, while route-not-found responses are wrapped by filters that continued.

Error disclosure risks include returning compiler, runtime, stack, panic, or internal state details. Framework errors use stable JSON code, message, and request_id fields and conformance tests assert common internal terms are not leaked for security preflight errors.

Proxy deployment risks include trusting spoofed X-Forwarded-* headers, forwarding hop-by-hop headers, and mismatched body limits between proxy and application. Treat proxy headers as untrusted unless the proxy overwrites them, and keep proxy limits at least as strict as ServerConfig.

Secure Defaults

Use web.default_server_config() as the starting point. It enables safe path checks, bounded request body size, bounded header count/name/value sizes, finite timeouts, method allow-listing including OPTIONS, bounded concurrency, and a graceful shutdown deadline.

Add web-specific security helpers from aicore_web_security:

let app1 = web.add_filter(app0, 1, security.security_headers_filter());
let app2 = web.add_filter(app1, 2, security.cors_filter("https://example.com"));

security.security_headers_filter() adds:

  • strict-transport-security: max-age=31536000; includeSubDomains
  • x-content-type-options: nosniff
  • referrer-policy: no-referrer
  • x-frame-options: DENY
  • content-security-policy: default-src 'none'; frame-ancestors 'none'

security.cors_filter(origin) uses a single explicit allowed origin, static allowed methods, static allowed headers, no credentials by default, and a finite preflight max age. Use security.with_cors_credentials only when the application has a separate credential and CSRF strategy.

Hardening Checklist

  • Keep require_safe_paths enabled unless a router-specific path normalization layer replaces it.
  • Set proxy and service request body limits consistently.
  • Keep max_header_count, max_header_name_bytes, and max_header_value_bytes small enough for the service.
  • Reject or overwrite all forwarding headers at the reverse proxy boundary.
  • Register security filters before application filters.
  • Prefer JSON as the primary request and response format.
  • Treat XML as a constrained flat-object format; do not use it for arbitrary documents.
  • Keep validation at request boundaries and use explicit validation errors.
  • Add service-specific CORS origins; do not reflect arbitrary origins.
  • Verify CI conformance stays green before release.

Non-Goals

  • TLS termination, certificate rotation, and mTLS are deployment concerns outside this package.
  • Authentication and authorization belong in aicore_auth, not aicore_web_security.
  • Generic cryptography belongs outside the web framework.
  • Full XML document processing, DTDs, external/custom entities, namespaces, attributes, duplicate fields, streaming XML, schema validation, and XPath are not supported.
  • HTTP keep-alive, pipelining, and streaming request bodies are not production-supported by the framework layer yet.

There aren’t any published security advisories