Why
v0.3.0 ships with several untrusted-input parsers that are excellent fuzz targets, currently covered only by unit tests:
- JWT parsing (
crates/agentpin/src/jwt.rs) — inline header/payload/signature parsing with algorithm rejection. AgentPin does NOT use a third-party JWT crate; algorithm validation is hand-rolled. Any malformed JWT must bounce off this code without panicking or hanging.
- JSON discovery doc parsing (
crates/agentpin/src/discovery.rs, crates/agentpin/src/types/*) — .well-known/agent-identity.json is fetched from untrusted publishers.
- A2A AgentCard parsing + canonicalisation for signing (
crates/agentpin/src/a2a.rs, crates/agentpin/src/types/a2a.rs) — wire format must round-trip byte-identically with the other three SDKs; canonical-form bugs are signature-bypass primitives.
- JWK ↔ PEM conversion (
crates/agentpin/src/jwk.rs) — public-key parsing, RFC 7638 thumbprint construction.
- DNS TXT record parsing (
crates/agentpin/src/dns.rs) — _agentpin.{domain} TXT values come from third-party DNS providers and registrars.
- Capability string parsing (
crates/agentpin/src/types/capability.rs) — wildcard/scope-matching grammar.
These are exactly the kinds of parsers where a single panic, infinite loop, OOM, or off-by-one is either a denial-of-service or (in the canonicalisation case) a potential signature-bypass.
Scope
- Add a new workspace member
crates/agentpin-fuzz/ using cargo-fuzz with at least one fuzz target per parser listed above.
- Provide a seed corpus for each target — JWTs issued by the test suite, real-world discovery doc JSON, AgentCards generated in Rust/JS/Python/Go interop tests, DNS TXT samples from the test vectors in
src/dns.rs.
- Add a scheduled GitHub Actions workflow (
.github/workflows/fuzz.yml, e.g. nightly at 02:00 UTC) that runs each target for a fixed time budget (5–10 minutes per target) and uploads any crashes as artifacts. Do not make this a PR-blocking check.
- Wire crashes back into the test suite as regression fixtures when found.
Non-goals (for the initial PR)
- Cross-language fuzzing (the JS/Python/Go SDKs would need their own harnesses — file separately if they accumulate enough parser surface to justify it). The wire format is shared so a corpus crash in Rust is likely a crash in all four.
- Long fuzz campaigns in CI — the scheduled workflow is intended as a smoke check, not a continuous-fuzzing service. Run longer campaigns locally before tagging a release.
Target release
v0.3.1 or v0.4.0. Not a v0.3.0 blocker — unit-test coverage of the parsers is solid, and adding fuzz targets requires writing per-parser harnesses across four SDKs to do properly. Better to ship v0.3.0 and follow up than to delay.
Context
Filed as a follow-up after a brief pre-release fuzz-coverage discussion during the v0.3.0 release. See https://github.com/ThirdKeyAI/AgentPin/releases/tag/v0.3.0 for what shipped.
Why
v0.3.0 ships with several untrusted-input parsers that are excellent fuzz targets, currently covered only by unit tests:
crates/agentpin/src/jwt.rs) — inline header/payload/signature parsing with algorithm rejection. AgentPin does NOT use a third-party JWT crate; algorithm validation is hand-rolled. Any malformed JWT must bounce off this code without panicking or hanging.crates/agentpin/src/discovery.rs,crates/agentpin/src/types/*) —.well-known/agent-identity.jsonis fetched from untrusted publishers.crates/agentpin/src/a2a.rs,crates/agentpin/src/types/a2a.rs) — wire format must round-trip byte-identically with the other three SDKs; canonical-form bugs are signature-bypass primitives.crates/agentpin/src/jwk.rs) — public-key parsing, RFC 7638 thumbprint construction.crates/agentpin/src/dns.rs) —_agentpin.{domain}TXT values come from third-party DNS providers and registrars.crates/agentpin/src/types/capability.rs) — wildcard/scope-matching grammar.These are exactly the kinds of parsers where a single panic, infinite loop, OOM, or off-by-one is either a denial-of-service or (in the canonicalisation case) a potential signature-bypass.
Scope
crates/agentpin-fuzz/usingcargo-fuzzwith at least one fuzz target per parser listed above.src/dns.rs..github/workflows/fuzz.yml, e.g. nightly at 02:00 UTC) that runs each target for a fixed time budget (5–10 minutes per target) and uploads any crashes as artifacts. Do not make this a PR-blocking check.Non-goals (for the initial PR)
Target release
v0.3.1 or v0.4.0. Not a v0.3.0 blocker — unit-test coverage of the parsers is solid, and adding fuzz targets requires writing per-parser harnesses across four SDKs to do properly. Better to ship v0.3.0 and follow up than to delay.
Context
Filed as a follow-up after a brief pre-release fuzz-coverage discussion during the v0.3.0 release. See https://github.com/ThirdKeyAI/AgentPin/releases/tag/v0.3.0 for what shipped.