From f7085d76f688e6b93811156133f1a435c7728a74 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Wed, 4 Nov 2026 14:50:24 +0000 Subject: [PATCH] Record security audit findings --- docs/roadmap/audit/07-security.md | 205 ++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 docs/roadmap/audit/07-security.md diff --git a/docs/roadmap/audit/07-security.md b/docs/roadmap/audit/07-security.md new file mode 100644 index 0000000..b666aa0 --- /dev/null +++ b/docs/roadmap/audit/07-security.md @@ -0,0 +1,205 @@ +# Security Audit + +Reviewed 2026-11-04 against commit `cf0bfd4` and the current worktree. Pending +relocations of earlier audit documents do not change the production baseline +and were left untouched. + +## Scope, Architecture, And Threat Boundary + +PromptKit is an in-process Go library with a public facade and internal +configuration, execution, transport, validation, and observation components. +ConfigKit owns source loading/composition; PromptKit interprets its final +handoff and captures immutable definitions. Execution reads caller-selected +artifacts, renders captured templates, resolves credentials, and contacts the +selected backend. Prepared handles privately retain one execution's settings. +Inspection and observation expose deliberately selected metadata. + +Reviewed configuration and request validation, filesystem/resource selection, +template and JSON handling, credential flow, public formatting and reports, +HTTP requests/redirect handling, provider responses, schema loading, repair, +backend capacity, prepared ownership, and release-entrypoint wiring. The review +included interactions with the selected ConfigKit and JSON Schema dependencies +and an advisory scan of runtime packages. + +The [architecture policy](../../policy/architecture.md#repository-and-consumer-boundary) +and [consumer security guidance](../../consumers/pkg-promptkit.md#protect-files-and-generated-data) +place application authorization, untrusted path/endpoint admission, payload-size +policy, and output disclosure with the consumer. Configuration sources, +templates, and injected Go collaborators are application-selected capabilities. +Upstream HTTP response bytes remain an external trust boundary. This review +does not treat ordinary file selection, runtime endpoint overrides, namespace +selection, or supported message roles as authorization mechanisms. + +No production code or repository tests were changed, no secrets were collected, +and no external provider or forge was probed. Network activity was limited to +obtaining the public Go vulnerability checker/database and reading official +advisories. This is a source review with focused diagnostics, not a claim that +every possible consumer deployment is secure. + +## Evidence + +- Source/call-graph review and the applicable public GoDoc, framework formats, + integration contract, policies, and ADR 0001. +- Existing focused tests passed for credential/report formatting, sensitive + configuration inspection/diffs, schema reference containment, provider-body + bounds, JSON value cycles/depth, prepared ownership, and capacity boundaries. +- A temporary offline public-API diagnostic used a controlled HTTP transport + and a synthetic credential. It verified the authentication-body behavior in + finding 2 and confirmed that credential was absent from the serialized report. +- `govulncheck` v1.9.0 scanned `./...` using Go 1.27.0 and the Go vulnerability + database last modified `2026-11-02T22:01:43Z`. The runtime scan covered the + module, its examples, ConfigKit v1.1.0, jsonschema/v6 v6.0.2, YAML v4.0.0-rc.6, + and x/text v0.14.0. It is not a complete audit of ReleaseKit's implementation + or every dependency used only by the release tool. + +The text-mode scan reported ten symbol-level standard-library advisories, plus +package/module-only matches. Those are candidate matches, not ten established +PromptKit vulnerabilities. Applicability was checked against the actual +operations described below rather than inferred from interface-call traces. + +## 1. The Audited Go Toolchain Predates Applicable Networking Security Fixes + +**Priority:** P2. Build/deployment security finding, not a newly discovered +PromptKit algorithm defect. + +**Relevant code:** [declared Go minimum](../../../go.mod:3), +[default HTTP-client construction](../../../internal/llm/openai_compatible_client.go:58), +[generation dispatch](../../../internal/llm/openai_compatible_client.go:211), and +[diagnostic dispatch](../../../internal/llm/http_evidence.go:129). + +**Condition and impact:** The local toolchain used for this audit is Go 1.27.0. +Applications built with that patch can exercise affected standard-library +networking through PromptKit's normal outbound client: + +- [GO-2026-6611](https://pkg.go.dev/vuln/GO-2026-6611) describes excessive CPU + consumption caused by a malicious HTTP/2 peer repeatedly changing initial + stream windows. An application using HTTP/2 against a hostile or compromised + backend, with enough active streams for amplification, can suffer availability + loss. The Go 1.27 fix is in 1.27.2. Body-size limits do not address protocol + processing below response decoding. +- [GO-2026-6809](https://pkg.go.dev/vuln/GO-2026-6809) adds explicit rejection of + compromised intermediate certificates. The affected conditions depend on the + platform and trust-store state. When the old trust path remains accepted, an + attacker able to present a matching certificate chain and intercept the + connection could compromise confidentiality/integrity of prompts, responses, + or bearer credentials. The Go 1.27 fix is in 1.27.3. This is not a claim that + every default system trust store remains affected. + +**Evidence and limits:** The advisories establish affected versions and attack +conditions; source review establishes use of the standard outbound HTTP/TLS +path. No certificate forgery, HTTP/2 attack, or running consumer binary was +tested. The scanner's surprising interface-based paths from unrelated methods +are not relied upon as proof of exploitation. PromptKit is source-only: a +consumer's actual compiled toolchain and transport configuration determine its +exposure. The `go 1.27.0` directive is a compatibility minimum, not a record of +which patch built an application. + +**Potential remediation:** Use an appropriate current patched Go toolchain, +at least 1.27.3 within this series for these two fixes, for release validation +and ReleaseKit execution; advise consumers to rebuild affected applications +with patched Go. Recheck advisories against that selected toolchain. This fits +the existing distinction between consumer minimum and maintainer toolchain in +the [release procedure](../../release.md#prepare-the-candidate). +Whether to raise the consumer minimum for the identified fixes is a separate +compatibility decision under the existing policy, not an automatic consequence +of this audit. These fixes do not require custom TLS verification, a blanket +HTTP/2 ban, or a new recurring release gate. + +## 2. Authentication Probes Permit Unbounded Remote-Body Memory Consumption + +**Priority:** P2. Existing availability finding, confirmed at the external +response boundary. This is the same mechanism as resource-management audit +finding 1, not a second independent remediation item. + +**Relevant code:** [authentication recognition](../../../internal/usecase/smoke_authentication.go:139), +[authentication probe execution](../../../internal/usecase/smoke_authentication.go:66), +and [diagnostic HTTP execution](../../../internal/llm/http_evidence.go:129). + +**Condition:** A consumer explicitly invokes an `openrouter_key` authentication +diagnostic. The selected endpoint, a compromised provider, or an intermediary +on an operator-selected plaintext connection returns HTTP 200 with a large or +continuously growing body. Recognition uses unrestricted `io.ReadAll` followed +by whole-document JSON unmarshalling. Unlike generation response decoding, +this path has no byte budget. HTTP-only probes also do not use generation +capacity admission. + +**Impact:** The remote peer controls memory consumption before the diagnostic +returns. A fast response can cause large allocations or process termination +before a deadline, and concurrent probes multiply the exposure. A configured +timeout bounds time, not bytes allocated during that interval. This requires a +diagnostic call; it is not an unauthenticated inbound attack on a PromptKit +server, and ordinary `Run` does not execute the probe. + +**Evidence:** The offline diagnostic returned a minimal recognized account +object and 4 MiB of irrelevant padding. PromptKit read all 4,194,374 bytes, +closed the body, and concluded with credential acceptance. The body used an +unknown content length. No deliberate memory exhaustion was attempted. The +synthetic bearer credential was supplied to the controlled transport and was +absent from the serialized diagnostic report. + +**Potential remediation:** Select a finite body budget for this small diagnostic +protocol and enforce it for declared and streamed lengths, closing on overflow +without unbounded draining. Preserve factual reporting: overflow establishes +neither credential rejection nor acceptance. Agree the limit and overflow +classification explicitly; no existing authentication-body byte guarantee is +being enforced. The existing resource-audit remediation can own this fix; +there is no need for separate global limits on prompts or artifacts. + +## Other Candidates And Boundary Checks + +- **Scanner applicability:** Server-only advisories GO-2026-6603, 6612, 6613, + and 6617 do not establish an attack on PromptKit's outbound client. ECH + server parsing (6607), multipart-form parsing (6608), and Range-serving + behavior (6609) likewise lack a matching operation here. The CONNECT-with-body + condition in 6605 and raw HTTP/2-to-HTTP/1 header forwarding in 6610 are absent + from built-in POST/GET generation and factual diagnostic reporting. Windows + junction-directory creation (6604) is not established by read-only resource + opens. These exclusions concern PromptKit, not all possible code in a host + application. +- **Module-only matches:** x/text advisories GO-2026-5970 and 6629 were not + reported as called vulnerable symbols; no matching use of `norm.Iter` or + `precis.Nickname` was established. html/template advisories 6599 and 6600 do + not apply to the text/template renderer. No separate runtime third-party + vulnerability was substantiated by this scan; that is not a general safety + certification of those modules. +- **Files and schemas:** Ordinary artifacts intentionally allow unrestricted + caller-selected regular files. Host-backed `content_file` contexts use + ConfigKit's rooted filesystem, while the standard schema loader checks + canonical containment and rejects remote reference schemes. Generic `fs.FS` + inputs remain caller-supplied capabilities; logical path checks do not turn an + arbitrary filesystem implementation into a host sandbox. No additional + confinement guarantee is proposed. +- **Injection:** Variables and artifact text are rendered as data rather than + reparsed as Go templates. Captured templates have the input helper and normal + text/template functionality, not a shell or process-execution helper. + Provider payloads use JSON encoding and reserved-field checks. Model output + is data for validation/repair, not executable code or an authorization + decision. Prompt injection and domain-aware interpretation remain consumer + concerns. +- **Credentials and disclosure:** Direct keys are request-scoped, excluded from + supported JSON and public request summaries, and removed from diagnostic + settings and prepared details. Provider error defaults redact details; + explicit provider accessors and arbitrary application content retain the + documented consumer disclosure responsibility. Inspection/diff tests protect + configured sensitive provider paths. No blanket redaction of arbitrary + prompt, schema, variable, error, or provider content is promised. +- **Ownership and availability:** Engine snapshots and copied public values + prevent ordinary cross-call mutation. Prepared handles enforce owner binding + and single claim. Capacity and retry cleanup are tested. Intentionally + unlimited backends, synchronous template/schema dependency calls, and + application-selected large files are not newly classified as vulnerabilities. + The other resource-audit findings remain maintenance items rather than + independently demonstrated remote attacks. +- **Release tooling:** Local launchers pass quoted arguments through `exec`; + there is no PromptKit runtime command-execution surface. The delivery token + path is ignored and selected for committed-file protection. Publication, + token-file permission enforcement, and recovery implementation belong to + ReleaseKit; no publication command was run during this audit. + +## Recommended Follow-Up + +Use a patched Go toolchain before release preparation and address the existing +authentication-body availability finding. Neither requires a new application +authorization subsystem or stronger filesystem, endpoint, or semantic-output +contracts. No additional PromptKit-specific confidentiality, integrity, or +authorization defect was substantiated within the documented boundary.