# Independent security review

This is the working brief for the review required before Open Print `1.0.0`.
The review must run in a context that did not author the implementation and
must produce reproducible evidence. Passing the project's own tests is
preparation for that review, not a substitute for it.

## Review baseline

Record the exact Git commit, package version, Node.js version, operating system,
and review date. Start from a clean checkout and run:

```bash
npm ci
npm run check
npm run test:security
npm run audit:production
npm run release:verify
```

The conformance fixture in `conformance/v1` and the independent Python verifier
are part of the review surface. Any changed fixture must be explained and
reproduced in both implementations.

## What to review

### Canonical encoding

- Review `src/encoding.ts` and `docs/CANONICALIZATION.md` together.
- Compare UTF-16 key order, string escaping, safe integers, negative zero,
  arrays, omitted object properties, cycles, and non-JSON objects.
- Confirm that the TypeScript and Python implementations hash the same UTF-8
  bytes for every conformance case.
- Look for distinct accepted inputs with the same unintended canonical form.

### Signatures and keys

- Trace the complete signed input for certificates, registry events, and
  checkpoints in `src/v1.ts` and `src/checkpoint.ts`.
- Confirm that algorithm, key ID, creation time, scope, payload, and integrity
  metadata are covered, while only the signature value is excluded.
- Test signature substitution across record types, issuers, keys, and validity
  windows.
- Review JWK import restrictions, canonical base64url decoding, Ed25519 failure
  handling, rotation, retirement, expiration, and revocation.
- Confirm that issuer schemas reject private JWK fields, extra key operations,
  wrong curves, wrong lengths, and non-canonical public-key encodings.
- Check whether any report can describe an unchecked signature as trusted.

### Registry and checkpoints

- Trace issuance, cancellation, supersession, uniqueness, and terminal-event
  rules in `src/v1.ts`.
- Try duplicate IDs, duplicate edition sequences, missing predecessors,
  reordered events, truncated histories, and two branches from one checkpoint.
- Confirm that only the original issuer can cancel or replace a certificate.
- Check empty registries, maximum safe sequences, and key-rotation boundaries.

### Archives and local storage

- Review nested archive relationships in `src/archive.ts`; recompute the outer
  digest after damaging each nested record.
- Review path handling, overwrite refusal, temporary names, file permissions,
  atomic replacement, stale locks, process failure, and concurrent writers in
  `src/node/file-store.ts`.
- Confirm the one-machine filesystem boundary and identify any unsupported
  network-filesystem assumptions.

### Untrusted input and command-line tools

- Exercise every validator with missing, additional, wrong-type, oversized,
  deeply nested, invalid UTF-8, and non-canonical base64url input.
- Confirm that verification returns an invalid report rather than throwing for
  JSON-shaped malformed records.
- Review the 64 MiB CLI boundary in `bin/read-json.mjs` and decide whether each
  deployment needs a smaller application limit.
- Check that errors do not expose private keys, local collector labels, or
  unrelated file contents.

### Release and dependency path

- Inspect the npm tarball allowlist, locked dependencies, SBOM, checksums,
  signed-tag check, GitHub attestations, and draft-release boundary.
- Reproduce the tarball from the reviewed tag and compare it byte for byte.
- Confirm that automation cannot publish to npm or publish a GitHub draft
  without a separate human decision.

## Finding format

Use one entry per finding:

```text
ID: OP-SEC-###
Severity: critical | high | medium | low | informational
Status: open | fixed | accepted | not-applicable
Affected commit:
Component:
Summary:
Attack prerequisites:
Impact:
Reproduction:
Recommended change:
Resolution and test:
```

Critical means practical private-key disclosure or broad acceptance of forged
trusted records. High means a practical integrity, issuer-authentication,
uniqueness, rollback, overwrite, or privacy failure. Medium requires meaningful
preconditions or has limited scope. Low and informational findings improve
hardening or clarity without breaking a stated security goal.

## Release decision

Before `1.0.0`:

- every critical and high finding must be fixed and covered by a regression
  test;
- every medium finding must be fixed or explicitly accepted with its remaining
  risk and owner;
- documentation must describe any accepted limitation that affects users;
- the reviewer must rerun the relevant checks against the final candidate;
- the reviewed commit must be identified by the signed release tag.

## Completed v1 release-candidate review

The AI-assisted adversarial review ran on 2 August 2026 against commit
`9ea12ac26059af050a6ffc74bcfea0f094b9266c`. It used a hash-verified snapshot,
separate specialist workstreams, deterministic exploit reproductions, and a
maintainer verification pass over every remediation.

The review identified one critical, four high, two medium, and two low
findings. Every finding was fixed and received regression coverage before the
first release candidate. No schema, canonicalization rule, signed input, or
conformance fixture changed. The method, findings, dispositions, and remaining
boundaries are recorded in
[SECURITY_REVIEW_RESULTS.md](SECURITY_REVIEW_RESULTS.md).

This record is deliberately described as AI-assisted rather than as a human
certification. A future human or institutional review can reuse the same brief,
bundle, reproductions, and finding format.
