206 lines
12 KiB
Markdown
206 lines
12 KiB
Markdown
# 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.
|