ADR-0007 — Archive format and in-memory static validation
Status: accepted, 2026-11-09.
Format
A release is one gzip-compressed tar (.tar.gz) holding the package directory. agent-registry.json at the root is the registry's wrapper manifest; upstream files (SKILL.md, package.json, pyproject.toml, MCP configuration) are preserved as they are.
The packer (writeArchive) is deterministic: entries sorted by path, mtime 0, uid/gid 0, modes normalised to 0644 or 0755, fixed gzip header. Packing the same directory twice gives the same bytes and therefore the same SHA-256.
Reader
packages/registry-core/src/tar.ts is a small strict reader written for this project rather than a general tar library:
- It never touches the filesystem. Bytes in, list of
{path, mode, data}out. - Decompression has a hard output cap, so a gzip bomb fails early.
- Regular files and directories only. Symlinks, hardlinks, devices, FIFOs and any other entry type abort the read. Base-256 size fields are refused.
- Header checksums are verified; a missing end-of-archive marker is an error.
- Limits: 20 MiB compressed, 64 MiB unpacked, 16 MiB per file, 2000 files.
- Paths are reported exactly as stored. The reader does not normalise them, so the validator sees what an extractor would see.
Validation
validatePackage is a pure function over the file list:
- Path safety: no absolute paths,
.., backslashes, control characters, drive letters, empty segments, non-NFC names, reserved device names, case-insensitive collisions; depth 16, length 240. - Forbidden files:
.git/,node_modules/,.env*(except.env.example,.env.sample,.env.template),.npmrc,.netrc,.ssh/,.aws/, private key files. - Manifest: strict zod schema, unknown keys rejected, 64 KiB cap. The manifest name and version must equal the artifact and version being published to.
- Type rules: a skill needs a spec-compliant
SKILL.mdwhosenameequals the slug; an MCP server needs anmcpblock and a README; other types need a README; a bundle needs exact-version dependencies. - Static scan of every text file: credential patterns (blocking), risky behaviour patterns and prompt-injection phrases (advisory).
The server additionally checks that the manifest type equals the artifact type and that dependencies resolve to visible artifacts with a satisfying published version.
Outcomes
- Any blocking finding: the upload is rejected, the staged bytes are deleted, nothing is published.
- Advisory findings with one of these codes send the release to quarantine for a moderator:
exec-pipe-to-shell,exec-encoded-payload,exec-destructive,exec-eval-remote,cred-access,prompt-exfiltration,prompt-concealment,prompt-override,text-bidi-control. - Otherwise the release is published with status
passed(no findings of medium severity or above) orflagged.
Non-goals
No package content is executed, imported, rendered as HTML or extracted to disk on the server. The scanner is advisory; passed means "no advisory findings from static checks", never "safe".