RFC dan proposal mencatat rancangan. Untuk kemampuan yang benar-benar dapat dipakai, lihat matriks kapabilitas runtime dan catatan rilis.
Appendix H security implementation status
This document compares the current YAZA source tree and runnable native API with Appendix H of the security blueprint. Appendix H is a target design, not a set of implemented guarantees. “Partial” means a named control exists in the current prototype; it does not imply broad or production-grade protection.
Security status reviewed against repository state: 2026-10-28. The review incorporated the supplied security additions and updated evidence/status records. Source-observed candidates remain unconfirmed unless a reproducible test is linked.
2026-10-28 descriptor-pressure and empty-EOF update: A controlled macOS loopback test lowers RLIMIT_NOFILE after server startup, forces a real accept() EMFILE, frees descriptors, verifies the yaza_http_accept_backoffs_total metric, waits for the one-second listener re-registration, and confirms new health traffic succeeds. The same harness confirms that an accepted peer closing before sending request bytes is reset without an HTTP 400 response or 400-status metric. Normal, ASan/UBSan, and ThreadSanitizer runs pass. The same harness verifies that a complete GET followed by shutdown(SHUT_WR) still receives 200, partial headers and bodies receive 400, the 400 response metric equals two, connection cleanup returns to baseline, and two matching 400 access records are logged. System-wide ENFILE and Linux epoll remain unverified.
2026-10-28 full connection-table overload update: If all YAZA_HTTP_MAX_CONNECTIONS slots are occupied, the event loop accepts and immediately closes excess TCP clients without attempting an HTTP response; this fixed overload policy avoids allocating request state or letting an unparsed slow client consume a slot. The saturating yaza_http_connections_rejected_total counter exposes these rejections at /metrics. A loopback regression holds the only slot, verifies the excess connection closes, confirms the active client can still read metrics, checks the counter, releases the slot, and confirms the listener accepts a new health request. The API concurrency harness passes normally, under ASan/UBSan, and under ThreadSanitizer on macOS. Linux epoll behavior remains unverified.
2026-10-28 API admission-capacity update: YAZA_API_MAX_IN_FLIGHT bounds queued, executing, and completed-but-undelivered controller/readiness jobs independently from the connection limit, defaulting to the connection capacity and allowing a lower configured cap. Invalid values fail before the listener opens. Queue saturation returns a fixed HTTP 503 and increments the worker-rejection metric; health and metrics continue to be served by the event loop. The normal, ASan/UBSan, and ThreadSanitizer worker harnesses passed on macOS with two active handlers, one queued job, a rejected fourth request, and operational endpoint checks. This reduces unbounded-work and overload risk but does not resolve non-cooperative handler occupancy, live PostgreSQL saturation, or Linux verification.
2026-10-28 PostgreSQL wait cancellation update: When API work waits for a pooled database lease, the pool now checks the request cancellation flag on each bounded wait cycle (at most 50 ms) and returns a fixed cancellation error promptly. The PostgreSQL pool harness, including a held lease and a cancelled waiter, passes normally and under ASan/UBSan and ThreadSanitizer on macOS. This releases worker capacity sooner after request cancellation or deadline expiry; it cannot interrupt a PostgreSQL query or socket operation already in progress, which remains bounded by its configured timeout.
2026-10-28 network wait cancellation update: Native TCP/TLS socket readiness waits now use at-most-50 ms poll slices while running in an API request and return when the request is cancelled. A socketpair regression holds a read with no incoming data, cancels its request, and requires the worker to return within 500 ms. The transport harness passes normally, under ASan/UBSan, and under ThreadSanitizer on macOS. This does not make the calls asynchronous, cancel synchronous DNS resolution, or prove interruption of every platform TLS-provider path; Linux and remote TLS remain unverified.
2026-10-28 bounded network-read allocation update: net_read now retains only the bytes actually received and frees its temporary maximum-sized buffer on EOF, timeout, cancellation, and other errors. The regression covers a 4-byte result from a larger request, 64 repeated 1 MiB timeouts with less than 16 KiB retained in the test arena, empty EOF with no retained buffer, and cancellation while a 1 MiB read waits. Normal, ASan/UBSan, and ThreadSanitizer checks pass on macOS. The arena bound is not an RSS guarantee, and Linux TLS-provider paths still need platform verification.
2026-10-28 repository scan evidence: I reran ./dist/yaza audit --security --format json from the repository root for this update. The latest run scanned 358 relevant files and emitted 15 heuristic candidates (five possible-secret matches and ten TLS-verification matches) with candidate values omitted; exit status 1 indicates findings. Context review confirmed that the compiler/native_cli.yz match is the scanner's own SARIF rule description, not a credential. The other possible-secret matches are synthetic test credentials, and the TLS matches are in test fixtures or local-development .env.example files; they are not evidence of a production secret or production TLS downgrade. Keep synthetic values and loopback-only examples clearly scoped, and repeat this review when those files change. This scan does not inspect dependency advisories, data flow, or runtime behavior and can miss or misclassify issues. Fifteen is not a CVE count, and the scan cannot prove the tree is clean. This workspace has no Git HEAD commit and the YAZA tree is uncommitted/untracked, so this result is tied to the current workspace snapshot, not an immutable release revision. No test suites were run as part of this documentation/status update.
2026-10-28 fatal-UBSan fuzz-gate update: Both libFuzzer and deterministic fallback builds now use -fno-sanitize-recover=undefined. tests/fuzz-regression-pipeline.sh verifies fatal behavior with a signed-overflow probe and passes locally. A 10,000-case macOS deterministic ASan/UBSan run replayed all six built-in HTTP/JSON seeds and completed without a finding. This closes the source/configuration gap in SEC-F01 locally; the hosted Ubuntu libFuzzer workflow has not yet been observed, so the Linux release gate remains pending.
2026-10-28 environment and child-process update: .env now uses no-follow open semantics, validates regular-file type, effective-user ownership, owner-only mode, a 1 MiB limit, and rejects embedded NUL bytes. It ignores loader, compiler/toolchain, sanitizer, interpreter-injection, and internal/test control keys while preserving shell-provided values. tests/dotenv-loader-smoke.sh passes on macOS arm64 for private-file loading and rejection of permissive mode, symlink, binary input, and reserved keys. The native compiler launches Clang using process_capture_env with only PATH and selected toolchain values; that API now rejects dynamic-loader variables while starting from exactly its explicit environment list. tests/process_environment.test.yz, JSON diagnostic checks, and the complete three-stage macOS bootstrap pass. This does not change ordinary process, process_capture, and timeout variants, which still inherit the parent environment; explicit allowlists also intentionally permit YAZA diagnostic metadata and sanitizer options when callers request them. Linux behavior is unverified.
2026-10-28 explicit child-environment update: Added process_env and process_timeout_env alongside process_capture_env; all three launch with only the caller-supplied environment. The shared validator rejects LD_*, DYLD_*, GCONV_PATH, and GLIBC_TUNABLES, and rejects an explicit PATH containing relative, empty, . or .. components. Process argument/environment lists are bounded to 256 entries, 8 KiB per entry, and 128 KiB aggregate bytes per list. The process test verifies exact captured environment, ambient-secret exclusion, loader-variable rejection, empty/traversal PATH rejection, oversized argument/environment-list rejection, successful explicit launch, and timeout termination. The full 45-test macOS bootstrap and the focused normal and ASan/UBSan process tests pass with these bounds. Legacy process, process_capture, and timeout calls intentionally keep inherited-environment behavior for compatibility; no executable allowlist or OS sandbox is provided, and Linux behavior is unverified.
2026-10-28 Host allowlist update: The HTTP runtime now checks each supplied Host against YAZA_ALLOWED_HOSTS, a maximum of 32 exact ASCII host names with no wildcard or configured port. Matching is case-insensitive and ignores the request port. Loopback defaults to 127.0.0.1, localhost, and the configured loopback address; a non-loopback bind without an explicit list is rejected before listening. The API HTTP smoke passes with wildcard configuration rejected, an unlisted hostile Host rejected, a configured mixed-case hostname accepted, and a non-loopback bind without a list refused. This reduces Host-header/DNS-rebinding exposure for the tested API path; it is not authentication, CORS, or TLS, and browser rebinding and Linux behavior remain unverified.
2026-10-28 HTTP 405 update: Runtime method-not-allowed responses now include an Allow header built from registered methods matching the requested path; built-in health, readiness, and metrics endpoints advertise GET. Route method names are validated as bounded ASCII HTTP tokens before the server listens. The API HTTP smoke verifies GET, POST for a collection, GET, PUT, PATCH, DELETE for an item, and GET for metrics. The full smoke passes on macOS normally and under ASan/UBSan. Header-size boundary behavior and Linux verification remain open; this is a protocol correctness fix, not evidence that the wider security profile is complete.
2026-10-28 shared-token overlap rotation: The runtime accepts a primary YAZA_API_TOKEN plus an optional distinct YAZA_API_TOKEN_SECONDARY, each validated to 32–1024 RFC Bearer-token bytes. When both slots are configured, the runtime compares both on every request using the fixed-width padded comparison; the comparison does not stop at the first matching slot. Secondary-only, malformed, undersized, and duplicate credentials fail startup without printing token values. The route-auth smoke accepts either credential and rejects invalid configuration normally and under ASan/UBSan on macOS; the full API HTTP CRUD smoke also passes, and the dotenv-loader smoke confirms .env loading. Hosted-target behavior remains a release gate. The documented rolling sequence installs the new credential as secondary everywhere, switches the primary while retaining the old credential as secondary, migrates clients, then removes the secondary. This supports overlap, not central revocation; exposure persists on instances still configured with the compromised token.
Summary
Appendix H is not complete. The current implementation is an early native compiler and an HTTP runtime that emits C, with event-loop-owned sockets and bounded worker threads for generated API handlers. It does not yet provide the type, ownership, isolation, standard-library, supply-chain, or governance foundations needed to make the blueprint's language-level security claims. Native C runtime code remains subject to C memory-safety defects even when hardening flags are enabled. Do not treat the current API as production-ready for sensitive data.
2026-10-28 security reassessment: The API/runtime still has no complete memory-safety proof, OS sandbox for untrusted source/tests, object/tenant authorization, inbound TLS, full Linux compiler/API verification, package provenance, or active private vulnerability-reporting process. The Linux epoll listener-event identity defect now has a source fix and a regression assertion in tests/io_backend.c; the native C harness suite passed locally on macOS with ASan/UBSan. That host exercises kqueue, so Linux epoll and Linux API end-to-end behavior remain unverified. Shared Bearer token startup now rejects values shorter than 32 bytes. The complete API HTTP smoke passed with a too-short token rejected and a 32-byte credential accepted; route authentication smoke passed normally and under ASan/UBSan. yaza secret token generates 32 OS-CSPRNG bytes as 64 lowercase hex characters; its smoke and the three-stage bootstrap passed. A minimum-length check cannot determine entropy for manually chosen values. Several supplied findings were stale against current code: normal HTTP responses use a bounded writable-event queue, the response header limit is 4,096 bytes, and the scheduler has deterministic core tests. See the integrated security proposal for the candidate register and corrected statuses. The findings are not confirmed CVEs or reproduced RCEs.
2026-10-28 supplied-additions review: The attached additions are treated as a source-review checklist, not as reproduced security findings. Their SEC-R01 observation now has a source fix and regression assertion, but Linux behavior remains unverified; SEC-R04, SEC-R07, SEC-R12, SEC-E01/E02, SEC-F01/F04, and SEC-S01 have newer implementation or CI-configuration evidence documented in the proposal. SEC-R02 is overstated unless a request-reachable failure is demonstrated. SEC-R09 remains a DNS-rebinding/Host hypothesis; SEC-B03 remains a code-generation boundary requiring adversarial tests, with no exploit reproduced. The integrated security assurance proposal records the threat model, evidence labels, prioritized finding register, OWASP API mapping, secure deployment baseline, verification/release gates, CVE intake and incident process, and a staged implementation order. The register has 13 P1-ranked follow-ups; this is a workload/risk-priority count, not a count of confirmed vulnerabilities. Appendix H currently has 2 of 18 sections implemented, 11 partial, 4 not implemented, and H.18 accepted as a design direction but pending implementation; these counts are not a weighted security score. No RCE or P0 was reproduced in this review, and that does not prove none exists. For this update I reran the read-only heuristic audit (358 files, 15 candidates); I did not rerun smoke, sanitizer, fuzz, or API suites. Previously recorded test/platform limits remain in force, and the current workspace has no immutable Git commit to identify a release revision.
2026-10-28 Linux readiness fix update: The I/O driver now records the descriptor registered with listener token 0; the Linux epoll adapter returns that descriptor for listener events, while task and response events keep their existing token-based dispatch. tests/io_backend.c asserts that a readable token-0 event carries the exact registered descriptor. sh scripts/runtime-c-sanitizers.sh passed locally on macOS, including this regression test. The existing Ubuntu 24.04 runtime-security workflow also compiles and runs this harness, but no hosted run is recorded here. Keep SEC-R01 open until that Linux job and a Linux API health/CRUD/shutdown smoke pass.
2026-10-28 accept-loop resilience update: The API listener retries interrupted/aborted accepts and guarded transient network errors, stops draining on EAGAIN/EWOULDBLOCK, and unregisters the listener for a one-second backoff after EMFILE/ENFILE. tests/io_backend.c covers classifier categories. The API concurrency harness now forces process-local EMFILE with a lowered RLIMIT_NOFILE, observes the backoff counter, and verifies recovery after the listener is re-registered; normal, ASan/UBSan, and ThreadSanitizer runs pass on macOS. System-wide ENFILE and Linux epoll behavior remain unverified. It also verifies that a queued client that closes before sending bytes does not yield a false HTTP 400 metric. SEC-R06 remains partial for system-wide and Linux behavior.
2026-10-27 scoped cleanup update: defer now runs an explicitly registered cleanup on lexical scope exit, return, ?, loop control, and nested branch exits. The API sanitizer smoke proves SecretText aliases are zeroized on both a successful response and a typed error response. Rollback failure and timeout now attempt to write a fixed structured event containing only the operation and closed-connection state. This does not make cleanup automatic for all secret values, erase the original immutable Text or environment storage, or provide unwind behavior after process termination. Memory ownership and destructor-based zeroization remain unimplemented.
2026-10-27 HTTP deadline update: The API request deadline, keep-alive idle timeout, and shutdown response-drain grace are configurable within bounded ranges. Defaults remain 5,000 ms; the runtime validates configuration at startup and reports effective values. A live loopback smoke verifies a configured 1,000 ms incomplete-request deadline, the matching keep-alive header, and shutdown-grace configuration. YAZA_HTTP_RESPONSE_WRITE_TIMEOUT_MS also configures the response-write deadline from 1,000 to 300,000 ms (default 5,000 ms). YAZA_HTTP_MAX_CONNECTIONS now sets the active-connection cap from 1 to 127 (default 64), bounded by the readiness-event buffer with one slot reserved for the listener; shutdown grace applies only to queued HTTP responses, not background work.
2026-10-28 route-scoped CORS update: Exact-origin CORS policies can be declared on routes or nested groups; group values inherit and a route value overrides its group, taking precedence over the server-wide origin. Actual responses and preflight use the matched route policy, and OpenAPI documents it as x-yaza-corsOrigin. HTTP smoke covers inheritance, overrides, denied origins, and preflight. Multi-origin lists and arbitrary middleware remain absent.
2026-10-28 safe HTTPS link authority update: std/html.yz now validates HTTPS link authorities before attribute escaping: DNS labels use bounded ASCII hostname syntax, IPv4 uses four canonical decimal octets, IPv6 literals must be bracketed and have valid group/compression counts, and explicit ports must be decimal 1–65535. It rejects malformed/ambiguous numeric hosts, user information, percent escapes in the authority, malformed ports, unbracketed IPv6, and IPv6 zone identifiers. tests/html.test.yz covers accepted DNS/IPv4/IPv6/port cases and rejected authority boundaries in normal and ASan/UBSan builds. This is link-target syntax validation, not a complete URL parser or an SSRF defense; IDN, IPv4-mapped IPv6, rich HTML sanitization, and context-typed trusted markup remain unimplemented.
2026-10-28 reusable HTTP/HTTPS URL parser update: std/url.yz now exposes url_parse_http(Text) -> Result[WebUrl, Text], returning the scheme, host and host kind, optional port, path, query, and fragment as typed fields. It bounds input to 8 KiB, accepts an ASCII URI subset with validated percent escapes, and checks DNS/strict IPv4/bracketed IPv6 authority syntax and decimal ports. std/html.yz reuses this parser for absolute HTTPS hrefs while retaining its separate relative-link policy and encoded-control checks. tests/url.test.yz and the integrated HTML tests pass normally and under ASan/UBSan. This is not a general URI parser: IDN, raw non-ASCII, IPv4-mapped/zone IPv6, relative-URL component parsing, path normalization, DNS resolution, and destination authorization remain unsupported; it is not an SSRF defense.
2026-10-27 bounded integer request validation: API shape declarations can apply validate <field> integer to numeric fields. The Float64 body decoder checks the exact decimal spelling and accepts only whole values in the IEEE-754 safe integer interval [-9007199254740991, 9007199254740991]; this avoids accepting fractions that round to whole Float64 values. Optional null/omitted fields skip validation; invalid values return a field-only error without echoing input. OpenAPI carries the same integer type and bounds. The complete HTTP and generation smokes pass normally and under ASan/UBSan. This narrows an API input contract; it does not establish general language-level integer safety or process memory limits.
H.1-H.18 status
| Section | Status | Implemented now | Missing from the blueprint |
|---|---|---|---|
| H.1 Guarantee boundaries | Partial | Documentation records that the compiler, runtime, and operator remain part of the trust boundary. | A reviewed security guarantee document tied to validated language semantics and release criteria. |
| H.2 Threat model | Implemented: version 1.2, reviewed 2026-10-28 | The maintained YAZA threat model identifies assets, actors, trust boundaries, abuse cases, current mitigations with source/test evidence, residual risks, and the release status of macOS, Linux, Windows, WASI/browser/edge, Android, and iOS targets. It incorporates route JWT/Host controls and links to the source-reviewed proposal and current/future risk horizon. It explicitly distinguishes local macOS evidence from unverified targets and defines review triggers. | Update the model as targets and controls change; target-specific validation and independent security review remain release gates tracked under H.6, H.13, H.15, and H.17. |
| H.3 Defense in depth | Partial | Bounded HTTP parsing, strict request framing, timeouts, parameterized PostgreSQL operations, optional bearer auth, CORS controls, hardened response headers, and hardened compiler flags exist. Result[Text, ApiError] and Result[Shape, ApiError] map every declared case to fixed status/error envelopes; InvalidInput.field and each ValidationFailed.errors entry are emitted only after strict bounded safe field-path checks for dotted identifiers and canonical array indexes from 0 through 63. The HTTP response writer normalizes legacy runtime status errors into the same nested error.type/error.code envelope, and auth/retry headers share the status response writer. OpenAPI lists common status/error schemas per operation. Unknown typed cases and unsafe payloads fall back to generic 500. A single typed contract for framework, authentication, and database errors remains absent. A disposable PostgreSQL 18.6 HTTP smoke now verifies SQLSTATE 23505, 23514, and 57014 as safe 409/409/504 responses, plus a safe 503 with Retry-After when PostgreSQL is terminated during an active create; server error details remain absent from response bodies. The defer-based rollback failure event contains only fixed operation/connection fields; its strict protocol test checks that PostgreSQL message text is absent from normal and sanitizer logs. |
Defense coverage across the language, standard library, dependency ecosystem, deployment targets, and security tests. |
| H.4 Memory-safe language | Partial | The native runtime has bounded program/request arenas and a unit-tested transfer/reset path. The latest 100,000-request API run retained the intended CRUD record and grew by 0 KiB sampled RSS at 1 KiB ps resolution (10,800 KiB baseline and peak); allocator and full CRUD/slow-client/timeout smoke pass under ASan/UBSan. These are runtime allocation controls only; the compiler still emits C. |
Ownership/borrowing, checked lifetime rules, complete index/arithmetic guarantees, non-null types, initialization guarantees, race-free isolation, and evidence that safe YAZA cannot cause undefined behavior. |
| H.5 Unsafe and FFI policy | Not implemented | No public YAZA unsafe or FFI feature is exposed. |
Unsafe blocks, SAFETY lint, package-level forbid policy, inventory/audit, reviewed FFI bindings, and runtime checking. Absence of these syntax features is not a memory-safety guarantee for the C runtime. |
| H.6 Compiler and binary hardening | Partial | Native builds enable stack-protector, PIE, fortified-library, and format-security compiler/linker options. yaza build --sanitize <file> -o <binary> adds ASan, UBSan, debug symbols, and frame pointers; debug/release modes are configurable. The 2026-10-27 self-host rebuild passed three native stages, and the final consecutive stages emitted identical C. A GitHub Actions workflow is configured to run C runtime harnesses under ASan/UBSan and require coverage-guided parser fuzzing on pushes, pull requests, and a weekly schedule; this workflow has not yet been observed on a hosted runner. The final macOS CLI has an ad-hoc local signature; the regenerated .pkg is unsigned and contains host-added AppleDouble provenance records. |
Reproducible independent builds, diverse double-compiling, signed provenance/release evidence, SBOM, hardened CI beyond the parser job, and a verified release pipeline. |
| H.7 Runtime limits and failure policy | Partial | HTTP header/body sizes are bounded; strict content-length and chunked framing is enforced, ambiguous framing is rejected, chunk lines/trailers are bounded, and framing/security fields in trailers are rejected. JSON objects are capped at 64 fields, duplicate keys are checked after escape decoding, malformed UTF-8 and unpaired surrogates are rejected, and the strict HTTP JSON parser rejects values at its 128-level recursion boundary. YAZA-owned kqueue/level-triggered epoll readiness code drives the event loop with at most the configured 1–127 connections (default 64); a separate fixed worker pool accepts 1–32 threads (default 4) and at most one in-flight job per connection. Only macOS has been exercised. The listener retries interrupted/aborted and guarded transient network accept() errors, stops draining on EAGAIN/EWOULDBLOCK, and pauses/unregisters for one second on EMFILE/ENFILE before re-registration; the native sanitizer harness, fixture API HTTP smoke, and a low-RLIMIT integration that forces process-local EMFILE and verifies listener recovery pass on macOS; system-wide ENFILE and Linux behavior remain unverified. The server exposes connection and worker queue/execution gauges at /metrics; normal and ASan/UBSan API smoke verifies worker and connection metrics, and a ThreadSanitizer integration verifies that two simultaneously blocked API handlers and one queued job stay within reported bounds, that a blocked readiness probe does not block health, that expired handlers return 504, and that timed-out work increments its metric. It incrementally reads each request, closes incomplete requests after a configurable absolute deadline (default 5,000 ms; YAZA_HTTP_REQUEST_TIMEOUT_MS accepts 1,000 to 300,000 ms), and queues responses under 16 MiB per response and 64 MiB aggregate pending-buffer limits. Writes flush in 64 KiB writable-event quanta with a configurable total deadline (default 5,000 ms; YAZA_HTTP_RESPONSE_WRITE_TIMEOUT_MS accepts 1,000 to 300,000 ms); buffer-cap or deadline failure closes the affected connection. HTTP/1.1 keep-alive has a configurable idle timeout (default 5,000 ms; YAZA_HTTP_KEEP_ALIVE_TIMEOUT_MS accepts 1,000 to 60,000 ms) and a 100-request connection cap; HTTP/1.0 and explicit close requests are not reused. SIGINT/SIGTERM stops accepts, collects readiness without blocking, completes requests already readable with Connection: close, and closes incomplete/idle sockets, then drains queued response bytes for up to the configured response-drain grace (default 5,000 ms; YAZA_HTTP_SHUTDOWN_GRACE_MS accepts 1,000 to 120,000 ms) before reaping remaining tasks; normal and ASan/UBSan smokes cover request and response drain. Queued worker jobs observe cancellation before execution; active handler code may poll http_request_cancelled() -> Boolean. The configured grace also bounds worker shutdown after response draining. If a C/YAZA handler ignores cancellation past the deadline, the process exits with failure instead of freeing runtime state while the worker is still using it. Raw TCP client handles are capped at 128, each read at 1 MiB, each write at 64 MiB, and each socket operation has a deadline; synchronous DNS lookup is not covered by the connect deadline. Each completed HTTP request gets a 64 MiB allocation budget, and the program arena has a 512 MiB allocation budget. PostgreSQL statements/locks and child processes have timeouts. Database readiness returns 503 within about 500 ms while PostgreSQL is paused and returns 200 after resume. Terminating PostgreSQL during an active create produces a redacted 503 with Retry-After. The disposable smoke restarts PostgreSQL on the same published host port and verifies readiness recovers in the same API process. Automatic retries are not implemented; the interrupted create returns 503. |
General CPU/stack and OS-level memory limits, limits for allocations outside the runtime allocator, parser budgets for formats beyond the current JSON parser, capacity sizing for worker-pool deployments, automatic cancellation of arbitrary user loops (handlers can poll http_request_cancelled() but may ignore it), hard preemption of non-cooperative handlers, request recovery, secret zeroization, core-dump policy, and OS sandboxing. Controller and PostgreSQL calls remain blocking within worker threads; non-cooperative handlers can occupy worker capacity, while health and socket writes remain event-loop-owned. Response output is nonblocking and limited to 64 KiB per event-loop turn, subject to the configurable response-write deadline (default five seconds). Arena caps are allocator accounting limits, not a process RSS limit. |
| H.8 Safe standard library | Partial | Initial YAZA-authored std/csv.yz parsing validates UTF-8 and quoting within a 16 MiB input cap, a 1 MiB decoded-field limit, and a 256-field row cap; tests/csv.test.yz covers valid rows and malformed input. YAZA-authored std/pdf.yz emits a deterministic one-page PDF 1.7 document from at most 80 printable ASCII bytes, escapes PDF text delimiters, and does not accept document actions or embedded content; this limited generator is not a general PDF writer. YAZA-authored std/html.yz escapes HTML text and quoted-attribute metacharacters, validates non-NUL UTF-8, and caps inputs at 64 KiB per chunk; tests/html.test.yz covers injection-shaped strings, quotes, Unicode, and output limits. std/url.yz adds a typed, bounded parser for an ASCII HTTP/HTTPS subset, exposing scheme, host kind, optional port, path, query, and fragment; it validates DNS/strict IPv4/bracketed IPv6 authorities, decimal ports, and percent-escape syntax. Absolute HTTPS href validation reuses this parser; relative hrefs use separate conservative printable-ASCII and percent-escape checks. Normal and ASan/UBSan URL and HTML tests cover accepted and rejected inputs. The parser does not support IDN, raw non-ASCII, IPv4-mapped/zone IPv6, relative URL components, path normalization, DNS resolution, or destination authorization; it is not an SSRF defense or general URI parser. Rich-HTML sanitization, JavaScript/CSS encoding, and typed safe-markup values remain absent. The HTTP parser validates Host syntax, requires JSON content type for non-empty bodies, rejects malformed framing and sensitive duplicate headers, validates UTF-8 and surrogate pairs, rejects decoded NUL in JSON strings, checks decoded JSON keys recursively for duplicates, safely percent-decodes path/query components, and Product CRUD SQL values use the YAZA PostgreSQL adapter's bound parameters; API startup, schema checks, and readiness also use the pure-YAZA client, and generated API binaries no longer link libpq. The API requires sslmode=verify-full for remote PostgreSQL startup; explicit sslmode=disable requires a numeric loopback host (or localhost pinned with loopback hostaddr) and is checked against the actual peer after connection. Normal and ASan/UBSan HTTP smokes reject remote disable/prefer/allow/require/verify-ca and unpinned localhost before network access. The current migration and database-configured API smoke passed against isolated PostgreSQL 18.6, including restart persistence, readiness pause/resume, live SQLSTATE-to-HTTP mappings, and active-create failure redaction; it also executes structured SELECT against a temporary relation and verifies injection-shaped query values stay bound. PostgreSQL 17.6 CRUD/restart evidence also exists. These local plaintext tests do not verify remote TLS or a broader server matrix. json_quote(Text) escapes quotes, backslashes, and control bytes; executable API handlers read metadata-validated Text path/query/header values and typed primitive path/query/body values as Option[T]. http_body_shape recursively decodes nested request shapes with required Text, Number, Int32, Float64, or Boolean leaves, optional scalar/nested fields, and optional TextList arrays of at most 64 strings and 1023 UTF-8 bytes per item; declared list item counts are checked before dispatch, Text validation counts Unicode code points, and decoded Text has a separate 1023-byte UTF-8 cap. Omitted and JSON null optional fields decode as none, and invalid or unknown values are rejected before dispatch. JSON body/schema validation errors return only a safe field path and fixed error code, never the submitted value; invalid items in TextList, List[Shape], and primitive typed arrays identify the bounded item index, while malformed containers and item-count errors identify the array field. Child processes use argument arrays, timeouts, bounded stdout/stderr capture, and an explicit-environment variant. Bytes and bounded binary file/stdin operations preserve arbitrary bytes including NUL; secure_random_bytes obtains bounded random data from the operating system. Low-level TCP and net_tls_client APIs provide bounded operations and a TLS 1.2+ client configured for system trust and hostname checks. std/db/query.yz builds a bounded SELECT descriptor and std/db/postgres.yz emits only validated, quoted identifiers and fixed comparison operators while binding values separately; this protects that structured query path, but it does not yet provide schema-checked native query syntax. pg_query_params remains available for explicit parameterized statements, and pg_query still accepts raw SQL for trusted static input only. Remote TLS and non-local PostgreSQL interoperability remain unverified. Explicit plaintext is restricted to PGSSLMODE=disable plus a loopback host and actual peer-address verification; a local protocol fixture passes normally and under ASan/UBSan. macOS uses deprecated Secure Transport and Linux provider/build behavior is unverified. |
Typed SQL/shape mapping, context-typed URL/JavaScript/CSS encoders and trusted-markup types, the complete safe filesystem API beyond rooted directory creation, listing, metadata, reads, and atomic replacement, archive/XML support and regex syntax beyond the bounded ASCII subset, SSRF-aware HTTP client, remote TLS and server-version coverage, cookie/CSRF/rate-limit APIs, executable allowlists/OS sandboxing, secret-safe file handling, deterministic byte-buffer ownership, and consistent safe defaults. |
| H.9 Cryptography | Partial | secure_random_bytes(Number) provides bounded OS randomness. SHA-256, HMAC-SHA-256, and PBKDF2-SHA-256 use CommonCrypto on macOS and OpenSSL on Linux; PBKDF2 inputs and rounds are bounded. bytes_equal_constant_time compares equal-length buffers without data-dependent early exit, and bytes_zeroize explicitly wipes bytes. The YAZA SCRAM-SHA-256 implementation checks the RFC 7677 proof and server-signature vector. std/crypto/password.yz wraps the external Argon2 reference provider with Argon2id PHC output, a random 16-byte salt, a 32-byte digest, fixed m=19456,t=2,p=1 parameters, a 1024-byte password cap, bounded encoded-hash validation, explicit wiping of temporary password/salt Bytes, verification, and rehash detection. The complete suite passed 33/33; the latest password test, including fresh-salt uniqueness and rejection of over-limit inputs, also passed separately under ASan/UBSan. The macOS package was built and pkgutil --payload-files confirmed the static archive, header, and license are present; a program also compiled and ran against the extracted provider bundle. The package has not been installed on a clean Mac, and the managed host adds AppleDouble records. Linux provider linking and verification remain untested. SCRAM rejects non-ASCII credentials until SASLprep support exists. |
Independent cryptographic review and provider update policy; AEAD, signatures, purpose-specific key types, deterministic secret ownership/zeroization (the original immutable Text is not erased), nonce lifecycle, KMS integration, clean installer testing, and full provider portability evidence. |
| H.10 Application security | Partial | API routes/groups support shared Bearer (auth required), explicit public (auth public), and JWT (auth jwt) policies. JWT verification accepts compact JWS HS256 only, requires typ: JWT, a 32–4096-byte configured secret, exact configured issuer and an aud string or non-empty string array containing the configured value, and integer exp; optional integer nbf and iat are checked. Unknown JOSE headers, padded/non-canonical base64url, malformed/duplicate JSON keys, invalid signatures, mismatched issuer/audience, and not-yet-valid tokens fail closed; a signature-valid expired token returns the stable token_expired response. JWT-only non-loopback binding requires at least one JWT route and an explicit auth policy on every declared route; missing JWT configuration is rejected at startup. During a matched JWT handler call, http_auth_claim_text(name) -> Option[Text] exposes a requested top-level string claim from the verified payload; each decoded value is capped at 1023 UTF-8 bytes, Unicode escapes are decoded, other routes get none, and the request-scoped payload buffer is wiped after dispatch. OpenAPI marks the bearer scheme and adds x-yaza-authentication: jwt-hs256; Postman creates Bearer requests. Normal and ASan/UBSan route middleware smokes check accepted/rejected tokens, string/array audience matching and malformed arrays, optional and Unicode claims, malformed subject, claim access on JWT-only mode, and spoofed-header rejection on public/shared-Bearer routes, alongside configuration and generator behavior. Shared Bearer auth has a 32-byte minimum and an optional distinct secondary credential for rolling overlap; both fixed-width candidates are compared when configured. Static bearer candidates are compared in a fixed 1,024-byte loop; JWT signatures use a fixed 32-byte comparison; duplicate Authorization headers fail closed. Loopback development may omit auth for routes with no policy. Exact-origin CORS, an exact Host allowlist (YAZA_ALLOWED_HOSTS, loopback defaults and mandatory explicit configuration for non-loopback binds), matched-controller custom-header checks, route/group inheritance and overrides, process-local IPv4 token buckets, bounded request validation, safe error envelopes, request IDs, and redacted access logs are also present as described in the runtime docs. The normal macOS API HTTP smoke rejects wildcard and unlisted Host values, accepts a configured mixed-case host, and refuses a non-loopback bind with no Host list. |
Login/token issuance, refresh and central revocation, JWT signing-key rotation and key IDs, asymmetric/JWKS/OIDC validation, a typed principal and centralized roles/permissions/ownership checks, MFA, actor-aware/distributed quotas, trusted-proxy identity, inbound TLS, complete secret lifecycle controls, and unified typed framework/auth/database failure conversion. JWT verification and claim access do not make application authorization decisions. |
| H.11 Package supply chain | Not implemented | Generated API binaries have no libpq link dependency; project templates pin a PostgreSQL container major version. |
Package registry, namespacing, lockfiles, signatures, provenance, dependency advisories, release-age controls, trusted publishing, sandboxed build scripts, and package audit commands. |
| H.12 Secrets and privacy | Partial | .env values are supported with shell precedence; access logs omit query strings; every HTTP response carries a 128-bit OS-random request ID that is also written to the structured access event, and CORS exposes it to browser clients; application log_event redacts common credential and personal-data field names; PostgreSQL API connection failures log only a generic redacted message, not server diagnostics or the connection URI. std/security/secret.yz adds an opaque SecretText value with a 64 KiB bound, environment loading, constant redaction, explicit reveal as Option[Text], and explicit zeroization shared by aliases. The compiler rejects implicit printing; JSON response serialization does not support the secret type. Normal and ASan/UBSan secret tests cover alias invalidation, redaction, reveal, environment lookup, and oversized input. |
Automatic lifetime/destructor zeroization, erasure of the original immutable Text or environment storage, synchronized concurrent access, complete data-flow redaction, typed PII, secret scanning integration, encrypted fields, data-retention tools, and end-to-end privacy review. Explicitly revealed Text aliases the secret buffer and can be copied by application code. Name-based log redaction can miss sensitive values under unfamiliar field names. |
| H.13 WASM, JavaScript, and edge | Not implemented | No compiler target for these environments is available. | WASM sandbox and imports, CSP-safe JavaScript output, edge secret bindings, bundle controls, and cross-target security conformance tests. |
| H.14 Security tooling | Partial | yaza audit --security --format json emits schema-versioned JSON with stable rule IDs, severity, heuristic confidence, path/line, redacted evidence, and explicit analyzer limits; --format sarif emits SARIF 2.1.0 with the matching four rule descriptors, rule indexes, warning-level results, percent-encoded relative artifact URIs, line regions where available, and redacted severity/confidence metadata. tests/audit-sarif.sh checks non-empty and empty reports, UTF-8/reserved-character path encoding, line-less scan-depth findings, rule-index consistency, invalid formats, and secret redaction; the macOS bootstrap runs this smoke and requires jq. Findings return status 1 while a clean scan returns 0. The text report uses the same findings. Native builds offer ASan/UBSan mode. scripts/fuzz-runtime.sh provides a libFuzzer target when available and a deterministic ASan/UBSan mutation runner otherwise. tests/json_depth.c, tests/memory_arena.c, and tests/secure_random.c pass locally under ASan/UBSan. A GitHub Actions workflow is configured to run those harnesses and 50,000 libFuzzer iterations using six version-controlled HTTP/JSON seed cases on pushes, pull requests, and a weekly schedule; failed runs upload fuzz artifacts. scripts/promote-http-fuzz-crash.sh stores a reviewed minimized input under a SHA-256-derived filename in tests/fuzz-corpus/; generated corpora include any committed regressions, and both the libFuzzer job and local fallback replay them. tests/fuzz-regression-pipeline.sh verifies promotion idempotence, symlink/size rejection, corpus assembly, and replay under ASan/UBSan using a temporary synthetic regression input. No real crash regression has been committed yet. Hosted workflow execution is not yet verified, and crash review/promotion remains a human step. See the fuzz regression workflow. The CLI test runner sorts discovery, builds tests from the project root, and runs each executable in a private per-test working directory with a combined compile-and-run timeout; it terminates the process group on timeout, reports timeouts separately, and continues after failures. Cleanup only permits owned mode-0700 /tmp/yaza-run.<suffix> trees, does not follow symlinks, and has depth/entry caps. This isolates relative working-directory files; it is not an OS sandbox. tests/test-runner-resilience.sh verifies timeout, later-test and compile-error continuation, working-directory isolation, and symlink-target preservation. Compiler failures include file and line locations in the supported source path. yaza check --format json [file.yz] emits versioned yaza.diagnostics JSON with percent-encoded file URIs, stable coarse codes, severity, message, related/notes arrays, and line-level fallback or statement-level UTF-8 byte ranges; tests/check-diagnostics.sh verifies valid and invalid source, statement-range columns, missing input, URI encoding, project entrypoint selection, and error exit status; the VS Code extension test verifies UTF-8-byte to UTF-16 mapping for an unsaved Unicode buffer. The diagnostics smoke passes with both native and ASan/UBSan CLI builds. JSON check aggregates up to three errors per function and start: body for import-free non-API files up to 96 KiB, 4,096 lines, and 32 functions, under a shared 128-probe budget. Up to two isolated recovery rounds can replace a typed initializer, supported return mismatch, or non-Boolean assert with a temporary type-correct statement while preserving source paths and lines. Other same-function errors, API sources, imports, malformed global declarations, unsupported return stubs, token-exact spans, and some lexer/parser failures remain incomplete. |
Other same-scope and imported/API/global recovery, token-exact spans, detailed diagnostic codes, broader analyzer coverage, dependency advisories, taint analysis, runtime verification, and hosted CI evidence. |
| H.15 Project security process | Not implemented | No private vulnerability-reporting channel or response commitment is configured. | SECURITY.md with a working private contact, coordinated disclosure, triage ownership, response targets, incident exercises, and public advisories. A placeholder contact would not satisfy this requirement. |
| H.16 OWASP mapping | Implemented: version 1.2 maps the current OWASP Top 10:2025 in the current web security mapping and the OWASP API Security Top 10:2023 in the API security mapping. The 2021 mapping remains as a historical record. | Each control is linked to repository evidence where available; missing dependency-security and SSRF controls are explicit. | Keep mappings aligned with implemented controls and review them when OWASP publishes a new baseline; these maps are not certifications or penetration tests. |
| H.17 Security roadmap gates | Partial | A push/pull-request/weekly CI workflow is configured to fail when the C runtime sanitizer harnesses or required libFuzzer job fail. This covers a narrow parser/runtime slice; the hosted workflow and repository branch-protection settings have not been verified. | Required branch-protection checks, complete compiler/API/PostgreSQL/target-build gates, ownership and memory-safety evidence, ecosystem security checks, release gates, and independent audit before 1.0. |
| H.18 Open decisions | Design direction accepted; implementation pending | The project owner accepted the RFC set on 2026-10-23. It covers memory/unsafe boundaries, supply chain, concurrency, secure APIs, targets, and release evidence. | Implement the accepted designs, incorporate them into the normative specification, and settle remaining details such as panic/recovery and capability boundaries before making security claims. |
H.7/H.10 HTTP OPTIONS authorization and discovery — 2026-10-28
The API now answers ordinary OPTIONS for registered and operational paths with a bodyless 204 and an Allow header built from the matched path; OPTIONS * reports the server-wide method set. Allow includes implicit HEAD for GET and OPTIONS itself. Unknown paths return 404. Authentication follows the most restrictive matching route policy, so a JWT-only route does not become discoverable anonymously; the route-auth smoke verifies rejection without a token and acceptance with a valid JWT. CORS preflight remains separate and still validates the requested method and headers. The complete API HTTP smoke passed on macOS; the route-auth smoke passed normally and under ASan/UBSan. Linux behavior remains unverified.
H.8 filesystem capability progress — 2026-10-24
std/fsroot.yz now exposes a bounded rooted-directory capability: open/close a generation-checked root handle, read bytes from a regular file below that root, and atomically replace a file below that root. Relative components reject ./.., absolute paths, empty components, controls, backslashes, malformed UTF-8, and symlinks; reads and writes are capped at 64 MiB. Replacement writes a private same-directory temporary file and renames it over the target, replacing a final symlink entry rather than following it. This provides atomic visibility but does not claim crash durability after power loss. The root path is selected by the application and resolved once when the capability is opened; the capability is not an OS sandbox.
tests/fsroot.test.yz checks language API behavior. tests/fsroot.c checks binary preservation, size limits, traversal, root/intermediate/final symlinks, stale handles, and concurrent replacement of a file with a symlink; the C harness passes normal and ASan/UBSan runs. At this 2026-10-24 checkpoint, directory listing, metadata and permission controls, descriptor streams, archive/XML support, regex syntax beyond the bounded ASCII subset, and cross-platform conformance were still missing. Later filesystem slices are recorded below; H.8 remains Partial.
H.8 rooted recursive directory creation — 2026-10-28
fs_root_create_directory(root, relative_path) now creates nested directories below an open root capability. It validates the complete bounded UTF-8 relative path before changing the filesystem, rejects absolute paths, empty/dot/traversal components, controls, backslashes, and more than 128 components, and walks each component through an opened directory descriptor with O_NOFOLLOW. New directories use owner-only 0700 mode subject to the process umask; existing directories are accepted only if they are real directories and are not chmodded. A filesystem failure during creation can leave already-created ancestors. This operation does not make the root handle an OS sandbox.
tests/fsroot.c now covers recursive and idempotent creation, private mode, invalid paths, file components, symlink components, and writing/reading a file under the created directory. tests/fsroot-language-smoke.sh exercises the public YAZA wrapper with a temporary root and a symlink escape fixture, normally and under ASan/UBSan. This closes directory creation only; at that checkpoint, metadata and permission APIs, descriptor streams, archive/XML support, and cross-platform evidence remained incomplete. H.8 remains Partial.
H.8 bounded rooted directory listing — 2026-10-28
fs_root_list_directory(root, relative_path) returns a bytewise-sorted TextList; an empty path lists the opened root itself. Non-empty paths are resolved component by component below duplicated directory descriptors with O_NOFOLLOW, and the final component must open as a directory. Symlink entries may be reported as names, but a later operation cannot use one to traverse outside the root. Names containing malformed UTF-8, control bytes, DEL, or backslash make the whole call fail rather than returning a partial or ambiguous result. The call rejects results above 4,096 entries or 512 KiB of combined filename bytes; it never silently truncates a listing. Allocation failure returns a fixed error and discards the partial list.
tests/fsroot.c covers deterministic ordering, root/nested/empty listings, traversal, symlink and regular-file rejection, the entry and byte caps, plus invalid UTF-8 rejection where the host filesystem permits such a filename. tests/fsroot-language-smoke.sh exercises the public API normally and under ASan/UBSan. These checks pass on macOS arm64; Linux and other target filesystems remain unverified. H.8 remains Partial: permission-changing APIs, additional metadata, descriptor streams, archive/XML support, and cross-platform conformance are still missing, and a rooted capability is not an OS sandbox.
H.8 rooted file metadata — 2026-10-28
fs_root_metadata(root, relative_path) -> Result[FsMetadata, Text] returns a typed shape containing kind, size_bytes, permissions, modified_seconds, and modified_nanoseconds. It reports only regular files and directories; directory size_bytes is defined as zero because directory sizes are filesystem-specific. permissions contains only the low nine POSIX permission bits (mode & 0777), and modification time preserves nanoseconds. The root itself is addressed with an empty relative path. Parent traversal uses the rooted no-follow resolver, and the final entry is inspected with fstatat(..., AT_SYMLINK_NOFOLLOW), so symlinks and special files fail closed without opening their targets. The API does not expose owner IDs, inode/device identity, access or creation time, or change permissions.
tests/fsroot.c checks file/directory kinds, byte size, private permission bits, timestamp bounds, traversal, symlink rejection, and invalid intermediate/final targets. tests/fsroot_directory_smoke.yz verifies the typed public shape; both language and C tests pass normally and under ASan/UBSan on macOS arm64. Linux and other platforms remain unverified. H.8 remains Partial: permission-changing APIs, additional metadata and descriptor streams, archive/XML support, and cross-platform conformance are outstanding; rooted file access is not an OS sandbox.
H.8 typed database value boundary — 2026-10-26
std/db/core.yz now distinguishes SQL NULL from empty text and zero-valued scalars with a tagged DbValue; typed accessors reject mismatched variants rather than coercing them. std/db/postgres.yz binds each supported value separately through the PostgreSQL protocol, and NULL requires an explicit type OID. The result adapter decodes only known integer, Boolean, finite Float64, text, and bytea OIDs; unsupported types and malformed/out-of-range floats return typed errors instead of coercing server data. Adapter errors use fixed categories and messages, not PostgreSQL server text. Unit coverage includes embedded NUL bytes preserved through bytea hex encoding and ASan/UBSan. Provider-neutral sessions, schema-to-shape derives, and a second driver remain absent.
Current runtime controls
Secret-zeroization clarification: H.7's remaining gap is automatic lifetime cleanup and coverage of all secret-bearing copies. The explicit SecretText and Bytes zeroization APIs are implemented and listed under H.12; they do not erase immutable source text, environment storage, or copies made by application code.
2026-10-26 bearer-authentication update: YAZA_API_TOKEN is validated as a 1–1024 byte Bearer token using the RFC token character set. The Bearer scheme is matched case-insensitively, duplicate Authorization fields fail closed, and comparison scans a fixed 1024-byte padded candidate before deciding, including on length mismatch. Temporary token-comparison buffers are wiped. This does not add a token issuer, rotation, users, roles, TLS, or actor-aware authorization.
2026-10-28 token-strength update: Startup validation now requires YAZA_API_TOKEN to be 32–1024 bytes while retaining the existing RFC Bearer character checks and fixed-width comparison. The complete API HTTP smoke rejects a short value and accepts a 32-byte test value. yaza secret token emits 32 OS-CSPRNG bytes as a 64-character lowercase hexadecimal value and wipes its temporary byte buffer; its smoke verifies output shape and two-call uniqueness. An optional secondary credential now enables bounded shared-token overlap rotation; when configured, both candidates are checked on every request and validated independently. See the rotation update above for scope and evidence. The minimum length is only a floor for user-provided values; this is not per-user token issuance or central revocation.
2026-10-26 update: API request shapes can apply bounded ASCII email syntax and a bounded anchored ASCII pattern subset before handler dispatch. Pattern matching uses fixed limits and dynamic programming without backtracking; regex unit, generation, and full API loopback smokes passed, including API smoke under ASan/UBSan. Email validation does not claim mailbox ownership or full internationalized support. These are input-validation controls, not a security guarantee for an application.
std/regex.yzexposesregex_pattern_is_validandregex_matchesover the anchored ASCII subset.tests/regex.test.yzcovers syntax rejection, classes, ranges, quantifiers, and maximum input/pattern boundaries. The engine deliberately rejects broader regex features until their semantics and resource bounds are specified.std/pg/protocol.yzimplements pure-YAZA PostgreSQL v3 startup and simple/extended query framing, bounded RowDescription, ErrorResponse, DataRow, and authentication parsing.std/pg/transport.yzimplements verified-TLS-by-default and explicitly loopback-only plaintext connection/startup/SCRAM flows and a simple-query response loop;pg_query_paramsuses separate bounded text Bind values and explicit SQL NULL flags. Both query paths return bounded single-command/single-result-set metadata and values, preserving SQL NULL, with accessors that decode supported text-format scalar types. The simple-query argument is raw SQL without parameters and must be trusted static text; bound user values belong inpg_query_params. The pure-YAZA transport completed a live local PostgreSQL 17.6 migration and generated API CRUD/restart-persistence smoke on 2026-10-25. A fake loopback server additionally verifies protocol boundaries normally and under ASan/UBSan. Remote TLS, broader server-version coverage, failure recovery, and connection pooling remain unverified.std/pg/scram.yzconstructs SCRAM-SHA-256 client proofs and checks the server signature in constant time. The RFC 7677 exchange vector and published SHA-256/HMAC/PBKDF2 vectors pass, including ASan/UBSan runs. Intermediate SCRAM key buffers are explicitly wiped. Unicode SASLprep is unsupported, so non-ASCII SCRAM credentials fail closed; typed shape mapping and pooling remain absent.- HTTP request headers are capped at 16 KiB and 64 fields; request bodies are bounded by the fixed parser buffer. Duplicate
Content-Length/Transfer-Encoding, conflicting length plus transfer encoding, unsupported transfer codings,Expect, malformed chunk framing/trailers, and invalid header controls are rejected. HTTP/1.1 chunked bodies are decoded within the request buffer cap. Runtime-managed allocations are accounted against 64 MiB per request and 512 MiB per program; this does not cap stack, native-library, or total process RSS. - HTTP/1.1
Hostvalues are syntax-checked and must match the configured exact host allowlist. Loopback defaults to127.0.0.1,localhost, and the configured loopback address; non-loopback binds requireYAZA_ALLOWED_HOSTS. The comma-separated list accepts at most 32 ASCII host names, rejects wildcards and ports, and matches case-insensitively while ignoring the request port. Non-empty request bodies requireapplication/json; path and query components are percent-decoded, while encoded path separators and controls are rejected. - The API binds to loopback by default and has a configurable port. YAZA-owned
kqueue/level-triggeredepollreadiness code drives an event loop that accepts at most the configured 1–127 active sockets (default 64), alongside a bounded 1–32-thread API worker pool. Only macOS has been exercised. The listener descriptor is now preserved in epoll events for token0; a regression assertion runs in the native readiness harness. The harness passed locally on macOS under ASan/UBSan, but Linux epoll and Linux API end-to-end behavior remain unverified until the Ubuntu workflow runs and a Linux API smoke is recorded. The loop supports bounded chunked request bodies and sequential/pipelined HTTP/1.1 requests up to 100 per connection, closes idle keep-alive sockets after the configured timeout (default 5,000 ms; YAZA_HTTP_KEEP_ALIVE_TIMEOUT_MS accepts 1,000 to 60,000 ms), and reads incomplete requests with the configured deadline (default 5,000 ms; YAZA_HTTP_REQUEST_TIMEOUT_MS accepts 1,000 to 300,000 ms). Conflicting length/transfer-encoding headers and malformed chunk framing are rejected. HTTP/1.0 and explicitConnection: closerequests close after one response. Response output is queued under 16 MiB per-response and 64 MiB aggregate pending-buffer limits, flushed on writable events in 64 KiB quanta, and closed after the configured response-write deadline (default 5,000 ms; YAZA_HTTP_RESPONSE_WRITE_TIMEOUT_MS accepts 1,000 to 300,000 ms). A socketpair harness verifies that a slow reader yields to another connection and later resumes. Smoke tests cover chunked CRUD, keep-alive reuse, pipeline ordering, slow-header fairness, and incomplete-request deadlines. Generated controller and readiness work runs on the bounded worker pool; PostgreSQL calls are still synchronous inside workers and use the YAZA connection pool. Normal/ASan/UBSan smoke covers 12 concurrent in-memory creates, and the API/readiness isolation harness passes ThreadSanitizer. Response writes remain event-loop-owned and nonblocking. Live PostgreSQL worker overlap and Linux behavior are not verified. - PostgreSQL connections use a five-second connect timeout, and each API connection sets statement, lock, and idle-transaction timeouts.
- Optional
YAZA_RATE_LIMIT_REQUESTSplusYAZA_RATE_LIMIT_WINDOW_MSenables a bounded token bucket per IPv4 peer address. It applies before authentication to valid non-operational requests, returns the generic 429 envelope with a calculatedRetry-After, and excludes health/readiness/metrics and CORS preflight. The 1,024-entry table rejects unknown clients when full until an idle entry expires. Normal and ASan/UBSan unit tests cover refill, separate clients, saturation and recovery; HTTP smoke covers configuration and responses. This is a process-local global route limiter, not a distributed quota, identity-aware policy or composable middleware. - The API's Product CRUD uses the pure-YAZA path and binds values separately through a checked
PgParametersbuilder for text, int8, int4, float8, Boolean, hex-text bytea, and SQL NULL values with PostgreSQL OIDs. It validates counts, OID ranges, NUL restrictions, and a 1 MiB aggregate value limit; external values must use bound parameters.pg_queryaccepts only trusted static SQL. Migration and the database-configured API smoke passed against isolated PostgreSQL 18.6; generated API startup/schema/readiness also use the pure-YAZA client and generated API binaries do not linklibpq. Live SQLSTATE 23505/23514/57014 mappings, readiness pause/resume, and forced PostgreSQL process loss during an active create pass with sanitized HTTP errors. Migration files run in transactions and are recorded with SHA-256 checksums; editing an applied migration is rejected. - Loopback API development may omit
YAZA_API_TOKENwhen route policies permit it. A non-loopback bind accepts either the shared token or JWT-only mode with at least one JWT route and explicit policy on every declared route. JWT uses only HS256 with pinned issuer/audience and required expiry; it is not an OIDC/JWKS verifier and does not implement roles. The sample's PostgreSQL Compose password is for local development only. CORS is disabled unless an exact origin is configured. - Access logs write to standard error and omit query strings. The application
log_eventAPI redacts common sensitive field names, but this heuristic is not complete secret or personal-data protection. yaza audit --securityreports file paths and line numbers for selected source/config patterns, but deliberately does not include candidate credential values in output.- Compiler errors in the native source compilation path include the active source file and line. JSON diagnostics batch up to three errors per eligible function/start: scope when type-correct local recovery applies, under a shared 128-probe budget; other source shapes still report the first error.
Required next security milestones
- Run Linux
.env, process-environment,io_backend, and end-to-end API health/CRUD/shutdown checks (SEC-E01/E02/R01); define inheritance for ordinary child-process APIs and migrate tool invocations to allowlists; exercise shared-token fleet rotation and design central revocation (SEC-R12); and verify fatal-UBSan fuzzing on hosted Ubuntu (SEC-F01). Source fixes and macOS smokes do not close Linux or release gates. - Implement RFC 0001 and RFC 0002; specify and test type, arithmetic, indexing, nullability, ownership, and concurrency rules before claiming memory safety.
- Implement RFC 0003 and RFC 0007; verify the hosted sanitizer/fuzz workflow, promote reviewed crashes into durable regression cases, then add dependency locks/advisories, broader CI gates, SBOM/provenance, and release evidence.
- Implement RFC 0004, RFC 0005, and RFC 0006; integrate PostgreSQL with the protocol modules, verify successful TLS handshakes on each target, then build the remaining typed safe APIs for SQL, paths, HTML, outbound HTTP, secrets, and authorization.
- Implement RFC 0008 before making security claims about WASM, edge, or mobile targets.
- Establish a private vulnerability contact and response process before public distribution; obtain independent review before 1.0. Accepted RFCs do not satisfy this operational requirement.